From 53aadbf4dbd17090df4e607a7ae39bcc1950a562 Mon Sep 17 00:00:00 2001 From: paunstefan Date: Thu, 5 Aug 2021 21:50:58 +0300 Subject: [PATCH] Added CRC8 support --- README.md | 2 +- benches/bench.rs | 14 ++++++++++- src/crc8.rs | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 ++- src/table.rs | 9 +++++++ src/util.rs | 16 ++++++++++++ tests/crc.rs | 12 +++++++++ 7 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 src/crc8.rs diff --git a/README.md b/README.md index ff0db24..e11c6d3 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Docs](https://docs.rs/crc/badge.svg)](https://docs.rs/crc) [![License](https://img.shields.io/crates/l/crc.svg?maxAge=2592000)](https://github.com/mrhooray/crc-rs#license) -Rust implementation of CRC(16, 32, 64). MSRV is 1.46. +Rust implementation of CRC(8, 16, 32, 64). MSRV is 1.46. ## Usage Add `crc` to `Cargo.toml` diff --git a/benches/bench.rs b/benches/bench.rs index 5fcdfcc..520e3f7 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -2,10 +2,21 @@ use crc::*; use criterion::{criterion_group, criterion_main}; use criterion::{Benchmark, Criterion, Throughput}; +pub const BLUETOOTH: Crc = Crc::::new(&CRC_8_BLUETOOTH); pub const X25: Crc = Crc::::new(&CRC_16_IBM_SDLC); pub const CASTAGNOLI: Crc = Crc::::new(&CRC_32_ISCSI); pub const ECMA: Crc = Crc::::new(&CRC_64_ECMA_182); +fn crc8(c: &mut Criterion) { + let mut digest = BLUETOOTH.digest(); + let bytes = vec![0u8; 1_000_000]; + c.bench( + "crc8", + Benchmark::new("crc8", move |b| b.iter(|| digest.update(&bytes))) + .throughput(Throughput::Bytes(1_000_000)), + ); +} + fn crc16(c: &mut Criterion) { let mut digest = X25.digest(); let bytes = vec![0u8; 1_000_000]; @@ -36,7 +47,8 @@ fn crc64(c: &mut Criterion) { ); } +criterion_group!(crc8_benches, crc8); criterion_group!(crc16_benches, crc16); criterion_group!(crc32_benches, crc32); criterion_group!(crc64_benches, crc64); -criterion_main!(crc16_benches, crc32_benches, crc64_benches); +criterion_main!(crc8_benches, crc16_benches, crc32_benches, crc64_benches); diff --git a/src/crc8.rs b/src/crc8.rs new file mode 100644 index 0000000..f37935d --- /dev/null +++ b/src/crc8.rs @@ -0,0 +1,64 @@ +use super::{Algorithm, Crc, Digest}; +use crate::table::crc8_table; + +impl Crc { + pub const fn new(algorithm: &'static Algorithm) -> Self { + let table = crc8_table(algorithm.poly, algorithm.refin); + Self { algorithm, table } + } + + pub const fn checksum(&self, bytes: &[u8]) -> u8 { + let mut crc = self.init(); + crc = self.update(crc, bytes); + self.finalize(crc) + } + + const fn init(&self) -> u8 { + if self.algorithm.refin { + self.algorithm.init.reverse_bits() + } else { + self.algorithm.init + } + } + + const fn table_entry(&self, index: u8) -> u8 { + self.table[index as usize] + } + + const fn update(&self, mut crc: u8, bytes: &[u8]) -> u8 { + let mut i = 0; + + while i < bytes.len() { + crc = self.table_entry(crc ^ bytes[i]); + i += 1; + } + + crc + } + + const fn finalize(&self, mut crc: u8) -> u8 { + if self.algorithm.refin ^ self.algorithm.refout { + crc = crc.reverse_bits(); + } + crc ^ self.algorithm.xorout + } + + pub const fn digest(&self) -> Digest { + Digest::new(self) + } +} + +impl<'a> Digest<'a, u8> { + const fn new(crc: &'a Crc) -> Self { + let value = crc.init(); + Digest { crc, value } + } + + pub fn update(&mut self, bytes: &[u8]) { + self.value = self.crc.update(self.value, bytes); + } + + pub const fn finalize(self) -> u8 { + self.crc.finalize(self.value) + } +} diff --git a/src/lib.rs b/src/lib.rs index 7b15491..7944e19 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ //! # crc -//! Rust implementation of CRC(16, 32, 64) +//! Rust implementation of CRC(8, 16, 32, 64) //! //! ## Usage //! ### Compute CRC16 @@ -35,6 +35,7 @@ pub use crc_catalog::*; mod crc16; mod crc32; mod crc64; +mod crc8; mod table; mod util; diff --git a/src/table.rs b/src/table.rs index 1599049..1e7ad75 100644 --- a/src/table.rs +++ b/src/table.rs @@ -1,5 +1,14 @@ use crate::util::*; +pub(crate) const fn crc8_table(poly: u8, reflect: bool) -> [u8; 256] { + let mut table = [0u8; 256]; + let mut i = 0; + while i < table.len() { + table[i] = crc8(poly, reflect, i as u8); + i += 1; + } + table +} pub(crate) const fn crc16_table(poly: u16, reflect: bool) -> [u16; 256] { let mut table = [0u16; 256]; let mut i = 0; diff --git a/src/util.rs b/src/util.rs index 317cfce..c378c23 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,3 +1,19 @@ +pub(crate) const fn crc8(poly: u8, reflect: bool, mut byte: u8) -> u8 { + if reflect { + byte = byte.reverse_bits() + }; + let mut value = byte; + let mut i = 0; + while i < 8 { + value = (value << 1) ^ ((value >> 7) * poly); + i += 1; + } + if reflect { + value = value.reverse_bits() + } + value +} + pub(crate) const fn crc16(poly: u16, reflect: bool, mut byte: u8) -> u16 { if reflect { byte = byte.reverse_bits() diff --git a/tests/crc.rs b/tests/crc.rs index cb65cee..7ee3238 100644 --- a/tests/crc.rs +++ b/tests/crc.rs @@ -2,6 +2,18 @@ use crc::*; const INIT: &[u8] = b"123456789"; +#[test] +fn crc_8() { + let algs = &[CRC_8_AUTOSAR, CRC_8_BLUETOOTH, CRC_8_SMBUS, CRC_8_DARC]; + for alg in algs { + let crc = Crc::::new(alg); + assert_eq!(alg.check, crc.checksum(INIT)); + let mut digest = crc.digest(); + digest.update(INIT); + assert_eq!(alg.check, digest.finalize()); + } +} + #[test] fn crc_16() { let algs = &[