Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added CRC8 support #63

Merged
merged 1 commit into from Aug 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -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`
Expand Down
14 changes: 13 additions & 1 deletion benches/bench.rs
Expand Up @@ -2,10 +2,21 @@ use crc::*;
use criterion::{criterion_group, criterion_main};
use criterion::{Benchmark, Criterion, Throughput};

pub const BLUETOOTH: Crc<u8> = Crc::<u8>::new(&CRC_8_BLUETOOTH);
pub const X25: Crc<u16> = Crc::<u16>::new(&CRC_16_IBM_SDLC);
pub const CASTAGNOLI: Crc<u32> = Crc::<u32>::new(&CRC_32_ISCSI);
pub const ECMA: Crc<u64> = Crc::<u64>::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];
Expand Down Expand Up @@ -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);
64 changes: 64 additions & 0 deletions src/crc8.rs
@@ -0,0 +1,64 @@
use super::{Algorithm, Crc, Digest};
use crate::table::crc8_table;

impl Crc<u8> {
pub const fn new(algorithm: &'static Algorithm<u8>) -> 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<u8> {
Digest::new(self)
}
}

impl<'a> Digest<'a, u8> {
const fn new(crc: &'a Crc<u8>) -> 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)
}
}
3 changes: 2 additions & 1 deletion 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
Expand Down Expand Up @@ -35,6 +35,7 @@ pub use crc_catalog::*;
mod crc16;
mod crc32;
mod crc64;
mod crc8;
mod table;
mod util;

Expand Down
9 changes: 9 additions & 0 deletions 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;
Expand Down
16 changes: 16 additions & 0 deletions 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()
Expand Down
12 changes: 12 additions & 0 deletions tests/crc.rs
Expand Up @@ -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::<u8>::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 = &[
Expand Down