pub(crate) mod config;
pub(crate) mod kernels;
pub(crate) mod keys;
pub(crate) mod portable;
#[allow(unused_imports)]
pub use config::{Crc16Config, Crc16Force};
#[cfg(any(test, feature = "std"))]
use crate::checksum::common::reference::crc16_bitwise;
use crate::checksum::common::{
combine::{Gf2Matrix16, combine_crc16, generate_shift8_matrix_16},
tables::{CRC16_CCITT_POLY, CRC16_IBM_POLY, generate_crc16_tables_8},
};
#[allow(unused_imports)]
pub(super) use crate::traits::{Checksum, ChecksumCombine};
#[cfg(target_arch = "aarch64")]
mod aarch64;
#[cfg(target_arch = "powerpc64")]
mod power;
#[cfg(target_arch = "riscv64")]
mod riscv64;
#[cfg(target_arch = "s390x")]
mod s390x;
#[cfg(target_arch = "x86_64")]
mod x86_64;
mod kernel_tables {
use super::*;
pub static CCITT_TABLES_8: [[u16; 256]; 8] = generate_crc16_tables_8(CRC16_CCITT_POLY);
pub static IBM_TABLES_8: [[u16; 256]; 8] = generate_crc16_tables_8(CRC16_IBM_POLY);
}
#[cfg(any(test, feature = "std"))]
#[inline]
fn crc16_ccitt_reference(crc: u16, data: &[u8]) -> u16 {
crc16_bitwise(CRC16_CCITT_POLY, crc, data)
}
#[cfg(any(test, feature = "std"))]
#[inline]
fn crc16_ibm_reference(crc: u16, data: &[u8]) -> u16 {
crc16_bitwise(CRC16_IBM_POLY, crc, data)
}
type Crc16DispatchFn = crate::checksum::dispatchers::Crc16Fn;
#[cfg(feature = "std")]
type Crc16DispatchVectoredFn = fn(u16, &[&[u8]]) -> u16;
#[cfg(feature = "std")]
#[inline]
fn crc16_apply_kernel_vectored(mut crc: u16, bufs: &[&[u8]], kernel: Crc16DispatchFn) -> u16 {
for &buf in bufs {
if !buf.is_empty() {
crc = kernel(crc, buf);
}
}
crc
}
#[inline]
fn crc16_ccitt_dispatch_auto(crc: u16, data: &[u8]) -> u16 {
let table = crate::checksum::kernel_table::active_table();
let kernel = table.select_fns(data.len()).crc16_ccitt;
kernel(crc, data)
}
#[inline]
fn crc16_ccitt_dispatch_auto_vectored(crc: u16, bufs: &[&[u8]]) -> u16 {
crc_vectored_dispatch!(crate::checksum::kernel_table::active_table(), crc, crc16_ccitt, bufs)
}
#[inline]
fn crc16_ibm_dispatch_auto(crc: u16, data: &[u8]) -> u16 {
let table = crate::checksum::kernel_table::active_table();
let kernel = table.select_fns(data.len()).crc16_ibm;
kernel(crc, data)
}
#[inline]
fn crc16_ibm_dispatch_auto_vectored(crc: u16, bufs: &[&[u8]]) -> u16 {
crc_vectored_dispatch!(crate::checksum::kernel_table::active_table(), crc, crc16_ibm, bufs)
}
#[cfg(feature = "std")]
#[inline]
fn crc16_ccitt_dispatch_reference(crc: u16, data: &[u8]) -> u16 {
crc16_ccitt_reference(crc, data)
}
#[cfg(feature = "std")]
#[inline]
fn crc16_ccitt_dispatch_portable(crc: u16, data: &[u8]) -> u16 {
portable::crc16_ccitt_slice8(crc, data)
}
#[cfg(feature = "std")]
#[inline]
fn crc16_ccitt_dispatch_reference_vectored(crc: u16, bufs: &[&[u8]]) -> u16 {
crc16_apply_kernel_vectored(crc, bufs, crc16_ccitt_reference)
}
#[cfg(feature = "std")]
#[inline]
fn crc16_ccitt_dispatch_portable_vectored(crc: u16, bufs: &[&[u8]]) -> u16 {
crc16_apply_kernel_vectored(crc, bufs, portable::crc16_ccitt_slice8)
}
#[cfg(feature = "std")]
#[inline]
fn crc16_ibm_dispatch_reference(crc: u16, data: &[u8]) -> u16 {
crc16_ibm_reference(crc, data)
}
#[cfg(feature = "std")]
#[inline]
fn crc16_ibm_dispatch_portable(crc: u16, data: &[u8]) -> u16 {
portable::crc16_ibm_slice8(crc, data)
}
#[cfg(feature = "std")]
#[inline]
fn crc16_ibm_dispatch_reference_vectored(crc: u16, bufs: &[&[u8]]) -> u16 {
crc16_apply_kernel_vectored(crc, bufs, crc16_ibm_reference)
}
#[cfg(feature = "std")]
#[inline]
fn crc16_ibm_dispatch_portable_vectored(crc: u16, bufs: &[&[u8]]) -> u16 {
crc16_apply_kernel_vectored(crc, bufs, portable::crc16_ibm_slice8)
}
define_crc_dispatch! {
word_ty: u16,
dispatch_fn_ty: Crc16DispatchFn,
dispatch_vectored_fn_ty: Crc16DispatchVectoredFn,
auto_force: Crc16Force::Auto,
force_expr: config::get_ccitt().effective_force,
active_table: crate::checksum::kernel_table::active_table(),
auto_dispatch: crc16_ccitt_dispatch_auto,
auto_vectored_dispatch: crc16_ccitt_dispatch_auto_vectored,
dispatch_cache: CRC16_CCITT_DISPATCH,
dispatch_vectored_cache: CRC16_CCITT_DISPATCH_VECTORED,
resolve_dispatch: resolve_crc16_ccitt_dispatch,
resolve_dispatch_vectored: resolve_crc16_ccitt_dispatch_vectored,
dispatch: crc16_ccitt_dispatch,
dispatch_vectored: crc16_ccitt_dispatch_vectored,
resolved_dispatch: crc16_ccitt_resolved_dispatch,
runtime_paths: crc16_ccitt_runtime_paths,
resolve_match: {
Crc16Force::Reference => crc16_ccitt_dispatch_reference,
Crc16Force::Portable => crc16_ccitt_dispatch_portable,
_ => crc16_ccitt_dispatch_auto,
},
resolve_vectored_match: {
Crc16Force::Reference => crc16_ccitt_dispatch_reference_vectored,
Crc16Force::Portable => crc16_ccitt_dispatch_portable_vectored,
_ => crc16_ccitt_dispatch_auto_vectored,
}
}
define_crc_dispatch! {
word_ty: u16,
dispatch_fn_ty: Crc16DispatchFn,
dispatch_vectored_fn_ty: Crc16DispatchVectoredFn,
auto_force: Crc16Force::Auto,
force_expr: config::get_ibm().effective_force,
active_table: crate::checksum::kernel_table::active_table(),
auto_dispatch: crc16_ibm_dispatch_auto,
auto_vectored_dispatch: crc16_ibm_dispatch_auto_vectored,
dispatch_cache: CRC16_IBM_DISPATCH,
dispatch_vectored_cache: CRC16_IBM_DISPATCH_VECTORED,
resolve_dispatch: resolve_crc16_ibm_dispatch,
resolve_dispatch_vectored: resolve_crc16_ibm_dispatch_vectored,
dispatch: crc16_ibm_dispatch,
dispatch_vectored: crc16_ibm_dispatch_vectored,
resolved_dispatch: crc16_ibm_resolved_dispatch,
runtime_paths: crc16_ibm_runtime_paths,
resolve_match: {
Crc16Force::Reference => crc16_ibm_dispatch_reference,
Crc16Force::Portable => crc16_ibm_dispatch_portable,
_ => crc16_ibm_dispatch_auto,
},
resolve_vectored_match: {
Crc16Force::Reference => crc16_ibm_dispatch_reference_vectored,
Crc16Force::Portable => crc16_ibm_dispatch_portable_vectored,
_ => crc16_ibm_dispatch_auto_vectored,
}
}
#[inline]
#[must_use]
pub(crate) fn crc16_ccitt_selected_kernel_name(len: usize) -> &'static str {
let cfg = config::get_ccitt();
if cfg.effective_force == Crc16Force::Reference {
return kernels::REFERENCE;
}
if cfg.effective_force == Crc16Force::Portable {
return kernels::PORTABLE_SLICE8;
}
let table = crate::checksum::kernel_table::active_table();
table.select_names(len).crc16_ccitt_name
}
#[inline]
#[must_use]
pub(crate) fn crc16_ibm_selected_kernel_name(len: usize) -> &'static str {
let cfg = config::get_ibm();
if cfg.effective_force == Crc16Force::Reference {
return kernels::REFERENCE;
}
if cfg.effective_force == Crc16Force::Portable {
return kernels::PORTABLE_SLICE8;
}
let table = crate::checksum::kernel_table::active_table();
table.select_names(len).crc16_ibm_name
}
#[derive(Clone, Copy)]
pub struct Crc16Ccitt {
state: u16,
dispatch: Crc16DispatchFn,
auto_table: Option<&'static crate::checksum::kernel_table::KernelTable>,
}
impl Crc16Ccitt {
const INIT: u16 = 0xFFFF;
const XOROUT: u16 = 0xFFFF;
const INIT_XOROUT: u16 = Self::INIT ^ Self::XOROUT;
const SHIFT8_MATRIX: Gf2Matrix16 = generate_shift8_matrix_16(CRC16_CCITT_POLY);
#[inline]
#[must_use]
pub const fn resume(crc: u16) -> Self {
Self {
state: crc ^ Self::XOROUT,
dispatch: crc16_ccitt_dispatch,
auto_table: None,
}
}
#[must_use]
pub fn config() -> Crc16Config {
config::get_ccitt()
}
#[must_use]
pub fn kernel_name_for_len(len: usize) -> &'static str {
crc16_ccitt_selected_kernel_name(len)
}
}
impl crate::traits::Checksum for Crc16Ccitt {
const OUTPUT_SIZE: usize = 2;
type Output = u16;
#[inline]
fn new() -> Self {
let (dispatch, auto_table) = crc16_ccitt_runtime_paths();
Self {
state: Self::INIT,
dispatch,
auto_table,
}
}
#[inline]
fn with_initial(initial: u16) -> Self {
let (dispatch, auto_table) = crc16_ccitt_runtime_paths();
Self {
state: initial ^ Self::XOROUT,
dispatch,
auto_table,
}
}
#[inline]
fn update(&mut self, data: &[u8]) {
if let Some(table) = self.auto_table {
if data.len() <= 7 {
self.state = portable::crc16_ccitt_bytewise(self.state, data);
return;
}
let kernel = table.select_fns(data.len()).crc16_ccitt;
self.state = kernel(self.state, data);
} else {
self.state = (self.dispatch)(self.state, data);
}
}
#[inline]
fn update_vectored(&mut self, bufs: &[&[u8]]) {
self.state = crc16_ccitt_dispatch_vectored(self.state, bufs);
}
#[inline]
fn finalize(&self) -> u16 {
self.state ^ Self::XOROUT
}
#[inline]
fn reset(&mut self) {
self.state = Self::INIT;
}
#[inline]
fn checksum(data: &[u8]) -> u16 {
crate::checksum::kernel_table::crc16_ccitt(data)
}
}
impl core::fmt::Debug for Crc16Ccitt {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Crc16Ccitt").finish_non_exhaustive()
}
}
impl Default for Crc16Ccitt {
fn default() -> Self {
<Self as crate::traits::Checksum>::new()
}
}
impl crate::traits::ChecksumCombine for Crc16Ccitt {
fn combine(crc_a: u16, crc_b: u16, len_b: usize) -> u16 {
combine_crc16(crc_a, crc_b, len_b, Self::SHIFT8_MATRIX, Self::INIT_XOROUT)
}
}
#[cfg(feature = "alloc")]
impl Crc16Ccitt {
#[must_use]
pub fn buffered() -> BufferedCrc16Ccitt {
BufferedCrc16Ccitt::new()
}
}
#[derive(Clone, Copy)]
pub struct Crc16Ibm {
state: u16,
dispatch: Crc16DispatchFn,
auto_table: Option<&'static crate::checksum::kernel_table::KernelTable>,
}
impl Crc16Ibm {
const INIT: u16 = 0x0000;
const XOROUT: u16 = 0x0000;
const INIT_XOROUT: u16 = Self::INIT ^ Self::XOROUT;
const SHIFT8_MATRIX: Gf2Matrix16 = generate_shift8_matrix_16(CRC16_IBM_POLY);
#[inline]
#[must_use]
pub const fn resume(crc: u16) -> Self {
Self {
state: crc ^ Self::XOROUT,
dispatch: crc16_ibm_dispatch,
auto_table: None,
}
}
#[must_use]
pub fn config() -> Crc16Config {
config::get_ibm()
}
#[must_use]
pub fn kernel_name_for_len(len: usize) -> &'static str {
crc16_ibm_selected_kernel_name(len)
}
}
impl crate::traits::Checksum for Crc16Ibm {
const OUTPUT_SIZE: usize = 2;
type Output = u16;
#[inline]
fn new() -> Self {
let (dispatch, auto_table) = crc16_ibm_runtime_paths();
Self {
state: Self::INIT,
dispatch,
auto_table,
}
}
#[inline]
fn with_initial(initial: u16) -> Self {
let (dispatch, auto_table) = crc16_ibm_runtime_paths();
Self {
state: initial ^ Self::XOROUT,
dispatch,
auto_table,
}
}
#[inline]
fn update(&mut self, data: &[u8]) {
if let Some(table) = self.auto_table {
if data.len() <= 7 {
self.state = portable::crc16_ibm_bytewise(self.state, data);
return;
}
let kernel = table.select_fns(data.len()).crc16_ibm;
self.state = kernel(self.state, data);
} else {
self.state = (self.dispatch)(self.state, data);
}
}
#[inline]
fn update_vectored(&mut self, bufs: &[&[u8]]) {
self.state = crc16_ibm_dispatch_vectored(self.state, bufs);
}
#[inline]
fn finalize(&self) -> u16 {
self.state ^ Self::XOROUT
}
#[inline]
fn reset(&mut self) {
self.state = Self::INIT;
}
#[inline]
fn checksum(data: &[u8]) -> u16 {
crate::checksum::kernel_table::crc16_ibm(data)
}
}
impl core::fmt::Debug for Crc16Ibm {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Crc16Ibm").finish_non_exhaustive()
}
}
impl Default for Crc16Ibm {
fn default() -> Self {
<Self as crate::traits::Checksum>::new()
}
}
impl crate::traits::ChecksumCombine for Crc16Ibm {
fn combine(crc_a: u16, crc_b: u16, len_b: usize) -> u16 {
combine_crc16(crc_a, crc_b, len_b, Self::SHIFT8_MATRIX, Self::INIT_XOROUT)
}
}
#[cfg(feature = "alloc")]
impl Crc16Ibm {
#[must_use]
pub fn buffered() -> BufferedCrc16Ibm {
BufferedCrc16Ibm::new()
}
}
#[cfg(feature = "alloc")]
const BUFFERED_CRC16_BUFFER_SIZE: usize = 256;
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
fn crc16_ccitt_buffered_threshold() -> usize {
crate::checksum::kernel_table::active_table().boundaries[0]
}
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
fn crc16_ibm_buffered_threshold() -> usize {
crate::checksum::kernel_table::active_table().boundaries[0]
}
#[cfg(feature = "alloc")]
define_buffered_crc! {
pub struct BufferedCrc16Ccitt<Crc16Ccitt> {
buffer_size: BUFFERED_CRC16_BUFFER_SIZE,
threshold_fn: crc16_ccitt_buffered_threshold,
}
}
#[cfg(feature = "alloc")]
define_buffered_crc! {
pub struct BufferedCrc16Ibm<Crc16Ibm> {
buffer_size: BUFFERED_CRC16_BUFFER_SIZE,
threshold_fn: crc16_ibm_buffered_threshold,
}
}
#[cfg(feature = "diag")]
impl crate::checksum::introspect::KernelIntrospect for Crc16Ccitt {
fn kernel_name_for_len(len: usize) -> &'static str {
Self::kernel_name_for_len(len)
}
}
#[cfg(feature = "diag")]
impl crate::checksum::introspect::KernelIntrospect for Crc16Ibm {
fn kernel_name_for_len(len: usize) -> &'static str {
Self::kernel_name_for_len(len)
}
}
#[cfg(test)]
mod tests {
extern crate std;
use super::*;
#[test]
fn test_vectors_crc16_ccitt_x25() {
assert_eq!(Crc16Ccitt::checksum(b"123456789"), 0x906E);
}
#[test]
fn test_vectors_crc16_ibm_arc() {
assert_eq!(Crc16Ibm::checksum(b"123456789"), 0xBB3D);
}
#[test]
fn test_combine_all_splits_ccitt() {
let data = b"The quick brown fox jumps over the lazy dog";
let full = Crc16Ccitt::checksum(data);
for split in 0..=data.len() {
let (a, b) = data.split_at(split);
let combined = Crc16Ccitt::combine(Crc16Ccitt::checksum(a), Crc16Ccitt::checksum(b), b.len());
assert_eq!(combined, full, "split={split}");
}
}
#[test]
fn test_streaming_resume_ibm() {
let data = b"The quick brown fox jumps over the lazy dog";
let oneshot = Crc16Ibm::checksum(data);
for &split in &[1, data.len() / 4, data.len() / 2, data.len().strict_sub(1)] {
let (a, b) = data.split_at(split);
let crc_a = Crc16Ibm::checksum(a);
let mut resumed = Crc16Ibm::resume(crc_a);
resumed.update(b);
assert_eq!(resumed.finalize(), oneshot, "Crc16Ibm resume failed at split={split}");
}
}
#[test]
fn test_streaming_resume_ccitt() {
let data = b"The quick brown fox jumps over the lazy dog";
let oneshot = Crc16Ccitt::checksum(data);
for &split in &[1, data.len() / 4, data.len() / 2, data.len().strict_sub(1)] {
let (a, b) = data.split_at(split);
let crc_a = Crc16Ccitt::checksum(a);
let mut resumed = Crc16Ccitt::resume(crc_a);
resumed.update(b);
assert_eq!(resumed.finalize(), oneshot, "Crc16Ccitt resume failed at split={split}");
}
}
#[cfg(feature = "alloc")]
#[test]
fn test_buffered_ccitt_matches_unbuffered() {
let data = b"The quick brown fox jumps over the lazy dog";
let expected = Crc16Ccitt::checksum(data);
let mut buffered = BufferedCrc16Ccitt::new();
for chunk in data.chunks(3) {
buffered.update(chunk);
}
assert_eq!(buffered.finalize(), expected);
}
#[cfg(feature = "alloc")]
#[test]
fn test_buffered_ibm_matches_unbuffered() {
let data = b"The quick brown fox jumps over the lazy dog";
let expected = Crc16Ibm::checksum(data);
let mut buffered = BufferedCrc16Ibm::new();
for chunk in data.chunks(3) {
buffered.update(chunk);
}
assert_eq!(buffered.finalize(), expected);
}
}
#[cfg(test)]
mod cross_check {
extern crate std;
use super::*;
use crate::checksum::common::tests::{STREAMING_CHUNK_SIZES, TEST_LENGTHS, generate_test_data};
#[test]
fn ccitt_all_lengths() {
for &len in TEST_LENGTHS {
let data = generate_test_data(len);
let reference = crc16_ccitt_reference(!0u16, &data) ^ !0u16;
let actual = Crc16Ccitt::checksum(&data);
assert_eq!(actual, reference, "CRC-16/CCITT mismatch at len={len}");
}
}
#[test]
fn ccitt_all_single_bytes() {
for byte in 0u8..=255 {
let data = [byte];
let reference = crc16_ccitt_reference(!0u16, &data) ^ !0u16;
let actual = Crc16Ccitt::checksum(&data);
assert_eq!(actual, reference, "CRC-16/CCITT mismatch for byte={byte:#04X}");
}
}
#[test]
fn ccitt_streaming_all_chunk_sizes() {
let data = generate_test_data(4096);
let reference = crc16_ccitt_reference(!0u16, &data) ^ !0u16;
for &chunk_size in STREAMING_CHUNK_SIZES {
let mut hasher = Crc16Ccitt::new();
for chunk in data.chunks(chunk_size) {
hasher.update(chunk);
}
let actual = hasher.finalize();
assert_eq!(
actual, reference,
"CRC-16/CCITT streaming mismatch with chunk_size={chunk_size}"
);
}
}
#[test]
fn ccitt_combine_all_splits() {
let data = generate_test_data(1024);
let reference = crc16_ccitt_reference(!0u16, &data) ^ !0u16;
for split in [0, 1, 15, 16, 17, 127, 128, 129, 511, 512, 513, 1023, 1024] {
if split > data.len() {
continue;
}
let (a, b) = data.split_at(split);
let crc_a = Crc16Ccitt::checksum(a);
let crc_b = Crc16Ccitt::checksum(b);
let combined = Crc16Ccitt::combine(crc_a, crc_b, b.len());
assert_eq!(combined, reference, "CRC-16/CCITT combine mismatch at split={split}");
}
}
#[test]
fn ccitt_unaligned_offsets() {
let data = generate_test_data(4096 + 64);
for offset in 1..=16 {
let slice = &data[offset..offset + 4096];
let reference = crc16_ccitt_reference(!0u16, slice) ^ !0u16;
let actual = Crc16Ccitt::checksum(slice);
assert_eq!(actual, reference, "CRC-16/CCITT unaligned mismatch at offset={offset}");
}
}
#[test]
fn ccitt_byte_at_a_time_streaming() {
let data = generate_test_data(256);
let reference = crc16_ccitt_reference(!0u16, &data) ^ !0u16;
let mut hasher = Crc16Ccitt::new();
for &byte in &data {
hasher.update(&[byte]);
}
assert_eq!(hasher.finalize(), reference, "CRC-16/CCITT byte-at-a-time mismatch");
}
#[test]
fn ccitt_reference_kernel_accessible() {
let data = b"123456789";
let expected = 0x906E_u16;
let reference = crc16_ccitt_reference(!0u16, data) ^ !0u16;
assert_eq!(reference, expected, "Reference kernel check value mismatch");
}
#[test]
fn ibm_all_lengths() {
for &len in TEST_LENGTHS {
let data = generate_test_data(len);
let reference = crc16_ibm_reference(0u16, &data);
let actual = Crc16Ibm::checksum(&data);
assert_eq!(actual, reference, "CRC-16/IBM mismatch at len={len}");
}
}
#[test]
fn ibm_all_single_bytes() {
for byte in 0u8..=255 {
let data = [byte];
let reference = crc16_ibm_reference(0u16, &data);
let actual = Crc16Ibm::checksum(&data);
assert_eq!(actual, reference, "CRC-16/IBM mismatch for byte={byte:#04X}");
}
}
#[test]
fn ibm_streaming_all_chunk_sizes() {
let data = generate_test_data(4096);
let reference = crc16_ibm_reference(0u16, &data);
for &chunk_size in STREAMING_CHUNK_SIZES {
let mut hasher = Crc16Ibm::new();
for chunk in data.chunks(chunk_size) {
hasher.update(chunk);
}
let actual = hasher.finalize();
assert_eq!(
actual, reference,
"CRC-16/IBM streaming mismatch with chunk_size={chunk_size}"
);
}
}
#[test]
fn ibm_combine_all_splits() {
let data = generate_test_data(1024);
let reference = crc16_ibm_reference(0u16, &data);
for split in [0, 1, 15, 16, 17, 127, 128, 129, 511, 512, 513, 1023, 1024] {
if split > data.len() {
continue;
}
let (a, b) = data.split_at(split);
let crc_a = Crc16Ibm::checksum(a);
let crc_b = Crc16Ibm::checksum(b);
let combined = Crc16Ibm::combine(crc_a, crc_b, b.len());
assert_eq!(combined, reference, "CRC-16/IBM combine mismatch at split={split}");
}
}
#[test]
fn ibm_unaligned_offsets() {
let data = generate_test_data(4096 + 64);
for offset in 1..=16 {
let slice = &data[offset..offset + 4096];
let reference = crc16_ibm_reference(0u16, slice);
let actual = Crc16Ibm::checksum(slice);
assert_eq!(actual, reference, "CRC-16/IBM unaligned mismatch at offset={offset}");
}
}
#[test]
fn ibm_byte_at_a_time_streaming() {
let data = generate_test_data(256);
let reference = crc16_ibm_reference(0u16, &data);
let mut hasher = Crc16Ibm::new();
for &byte in &data {
hasher.update(&[byte]);
}
assert_eq!(hasher.finalize(), reference, "CRC-16/IBM byte-at-a-time mismatch");
}
#[test]
fn ibm_reference_kernel_accessible() {
let data = b"123456789";
let expected = 0xBB3D_u16;
let reference = crc16_ibm_reference(0u16, data);
assert_eq!(reference, expected, "Reference kernel check value mismatch");
}
#[test]
fn ccitt_portable_matches_reference() {
for &len in TEST_LENGTHS {
let data = generate_test_data(len);
let reference = crc16_ccitt_reference(!0u16, &data) ^ !0u16;
let portable = portable::crc16_ccitt_slice8(!0u16, &data) ^ !0u16;
assert_eq!(portable, reference, "CRC-16/CCITT portable mismatch at len={len}");
}
}
#[test]
fn ibm_portable_matches_reference() {
for &len in TEST_LENGTHS {
let data = generate_test_data(len);
let reference = crc16_ibm_reference(0u16, &data);
let portable = portable::crc16_ibm_slice8(0u16, &data);
assert_eq!(portable, reference, "CRC-16/IBM portable mismatch at len={len}");
}
}
}
#[cfg(test)]
crate::define_crc_property_tests!(crc16_ccitt_props, Crc16Ccitt);
#[cfg(test)]
crate::define_crc_property_tests!(crc16_ibm_props, Crc16Ibm);