Skip to main content

Crate crc32_v2

Crate crc32_v2 

Source
Expand description

ยงโšก CRC32-V2

CRC32-V2 Logo

Crates.io Docs.rs Build Status PyPI npm License: MIT

The fastest pure-software, no_std-compatible CRC-32 implementation in Rust, slicing-by-16 tables, zero heap allocation in the hot path, and native Python / Node.js bindings, all written in 100% safe Rust ๐Ÿ—ฟ.

Banger Banner

ยง๐Ÿš€ Installation

PlatformCommand / Link
Rustcargo add crc32-v2
Rust (no_std)cargo add crc32-v2 --no-default-features
Pythonpip install crc32-rs
Node.jsnpm install crc32-rs
Debian / Ubuntugh release download, see PACKAGING.md
RHEL / Fedoragh release download, see PACKAGING.md

ยง๐Ÿ”ญ Features

FeatureDescription
no_std + allocEmbeddable in bare-metal, WASM, and embedded targets, no standard library required
100% safe Rust#![forbid(unsafe_code)] enforced crate-wide; zero unsafe blocks
crc32Byte-at-a-time baseline (~343 MiB/s); compatible with zlib, PKZIP, Ethernet, and FDDI
crc32_littleSlicing-by-4 (~833 MiB/s); 2.4ร— faster than byte-at-a-time
crc32_little_8Slicing-by-8 (~1,004 MiB/s); 2.9ร— faster than byte-at-a-time
crc32_little_16Slicing-by-16 (~1,282 MiB/s); 3.7ร— fastest pure-software path
crc32_bigBig-endian (unreflected) variant for hardware CRC controllers
crc32_combineMerge two independently computed CRCs in O(log n) via GF(2) matrix squaring
Streaming DigestIncremental checksum with zero-copy buffering
Build-time tablescrc32-codegen subcrate generates all 16 lookup tables at compile time
Python bindingsVia PyO3 / maturin (pip install crc32-rs)
Node.js bindingsVia napi-rs (npm install crc32-rs)

ยง๐Ÿฆ€ Rust

ยงOne-shot checksum

use crc32_v2::crc32;

let data = b"Hello, world!";
println!("CRC-32: {:#010X}", crc32(0, data));  // CRC-32: 0xEBE6C6E6
assert_eq!(crc32(0, b"123456789"), 0xCBF43926);

ยงSlicing-by-16 (fastest pure-software path, ~1,282 MiB/s)

use crc32_v2::byfour::crc32_little_16;

let data: Vec<u8> = (0..1_048_576).map(|i| i as u8).collect();
let crc = crc32_little_16(0, &data);
println!("CRC-32: {crc:#010X}");
assert_eq!(crc32_little_16(0, b"123456789"), 0xCBF43926);

ยงSlicing-by-8 (~1,004 MiB/s)

use crc32_v2::byfour::crc32_little_8;

let crc = crc32_little_8(0, b"Hello, world!");
assert_eq!(crc, 0xEBE6_C6E6);

ยงSlicing-by-4 (~833 MiB/s)

use crc32_v2::byfour::crc32_little;

let crc = crc32_little(0, b"Hello, world!");
assert_eq!(crc, 0xEBE6_C6E6);

ยงCombining two checksums without the original data

use crc32_v2::{crc32, crc32_combine};

let crc1 = crc32(0, b"Hello, ");
let crc2 = crc32(0, b"world!");
let combined = crc32_combine(crc1, crc2, b"world!".len() as u64);
assert_eq!(combined, crc32(0, b"Hello, world!"));

ยงStreaming Digest

use crc32_v2::Digest;

let mut digest = Digest::new();
digest.update(b"Hello, ");
digest.update(b"world!");
println!("CRC-32: {:#010X}", digest.finalize()); // 0xEBE6C6E6
let bytes: [u8; 4] = digest.digest();            // [0xEB, 0xE6, 0xC6, 0xE6]

ยงno_std usage

[dependencies]
crc32-v2 = { version = "0.2.0", default-features = false }
โ“˜
#![no_std]

use crc32_v2::{crc32, byfour::crc32_little_16, Digest};

let crc = crc32_little_16(0, b"embedded payload");
assert!(crc != 0);

ยง๐Ÿ Python

See PYTHON.md for the full API reference.

pip install crc32-rs
from crc32_rs import crc32, crc32_little_16, crc32_bytes, crc32_hex, Digest

print(hex(crc32(b"Hello, world!")))             # 0xebe6c6e6
print(hex(crc32_little_16(b"Hello, world!")))   # 0xebe6c6e6
print(crc32_bytes(b"Hello, world!").hex())      # ebe6c6e6
print(crc32_hex(b"Hello, world!"))              # ebe6c6e6

d = Digest()
d.update(b"Hello, ")
d.update(b"world!")
print(hex(d.finalize()))   # 0xebe6c6e6
print(d.digest().hex())    # ebe6c6e6
print(repr(d))             # Digest(crc=0xEBE6C6E6)

ยง๐ŸŸฉ Node.js

See NODE.md for the full API reference.

npm install crc32-rs
const { crc32, crc32Little16, Digest } = require("crc32-rs");

console.log(crc32(Buffer.from("Hello, world!")).toString(16)); // ebe6c6e6
console.log(crc32Little16(Buffer.from("Hello, world!")).toString(16)); // ebe6c6e6

ยง๐Ÿ“Š Benchmarks

Measured with cargo bench (lto="fat", opt-level=3, codegen-units=1, overflow-checks=false) on Linux x86-64 (Rust 1.94.1). Full methodology in BENCHMARKS.md.

ยงThroughput across payload sizes

Method1 B64 B1 KiB64 KiB1 MiBThroughput
crc32_v2::crc322 ns167 ns2,856 ns188,134 ns2,916,562 ns~343 MiB/s
crc32_v2::crc32_little3 ns73 ns1,086 ns82,129 ns1,199,953 ns~833 MiB/s
crc32_v2::crc32_little_83 ns61 ns922 ns56,486 ns1,004,746 ns~1,004 MiB/s
crc32_v2::crc32_little_163 ns39 ns753 ns48,101 ns781,535 ns~1,282 MiB/s
crc32fast::hash (SIMD)11 ns20 ns102 ns5,802 ns89,204 ns~11,300 MiB/s

ยงCross-library comparison: 1 MiB payload

LibraryMethodTimeThroughputImplementation
crc32fasthash89,204 ns~11,300 MiB/sSIMD (pclmulqdq) / Rust
zlib-rscrc3296,968 ns~10,390 MiB/sSIMD / Rust
Python (zlib)zlib.crc32355,270 ns~2,815 MiB/sSIMD / C extension
crc32-v2crc32_little_16781,535 ns~1,282 MiB/sPure safe Rust
Python (crcmod)crcmod2,865,836 ns~349 MiB/sNon-SIMD / C extension

ยงPython overhead: small inputs

PayloadPython zlib.crc32Rust crc32-v2Speedup
1 B~297 ns~2 ns~148ร—
64 B~301 ns~39 ns~7.7ร—

Key takeaways

  • crc32_little_16 achieves ~1,282 MiB/s, the fastest pure-software, safe-Rust CRC-32 path, 3.7ร— faster than byte-at-a-time.
  • For inputs โ‰ค 1 byte, crc32 (2 ns) wins because slicing variants pay an alignment-prologue cost.
  • crc32fast achieves ~11 GiB/s via runtime hardware SIMD. For no_std, embedded, or WASM targets, use crc32-v2.
  • Python interpreter overhead dominates for small payloads: Rust is 148ร— faster for 1-byte inputs.

ยง๐Ÿ—‚ Module Structure

ModuleContents
tablescrc32: byte-at-a-time CRC-32 function
byfourcrc32_little / crc32_little_8 / crc32_little_16 / crc32_big
combinecrc32_combine: O(log n) GF(2) matrix merging
digestDigest: streaming incremental interface
crc32tables16 LE slicing tables + BE table (generated by crc32-codegen at build time)

ยง๐Ÿ”’ Safety

#![forbid(unsafe_code)] is enforced at the crate root. Every byte of the implementation, 16-table generation, slicing loops, GF(2) matrix arithmetic, and the streaming Digest, is written in safe Rust. The no_std build path carries the same safety guarantees.

ยง๐Ÿ“š Further Reading

[!NOTE] This project is a successor of the awesome crc32 crate created by the kawaii engineers at Microsoft ๐Ÿ‘‰๐Ÿ‘ˆ.

ยง๐Ÿ“„ License

Licensed under the MIT License.

ยงcrc32-v2 Rust Documentation ๐Ÿฆ€

The crc32-v2 Rust crate provides a pure-software, 100%-safe-Rust CRC-32 implementation with slicing-by-4/8/16 high-throughput variants, a streaming Digest type, O(log n) CRC combining, and native Python / Node.js bindings.

ยง๐Ÿ“ฆ Installation

[dependencies]
crc32-v2 = "0.2.0"

ยง๐Ÿ—‚ Module Structure

ModuleContents
tablescrc32: byte-at-a-time CRC-32 (IEEE 802.3, ~343 MiB/s)
byfourcrc32_little / crc32_little_8 / crc32_little_16 / crc32_big
combinecrc32_combine: O(log n) GF(2) matrix merging
digestDigest: streaming incremental checksum
crc32tables16 LE slicing tables + BE table (build-time, crc32-codegen)

ยง๐Ÿ›  Core Functions

ยงcrc32: One-shot checksum

use crc32_v2::crc32;

assert_eq!(crc32(0, b"123456789"), 0xCBF43926);

let crc = crc32(crc32(0, b"Hello, "), b"world!");
assert_eq!(crc, crc32(0, b"Hello, world!"));

ยงcrc32_little_16: Fastest pure-software path (~1.3 GiB/s)

use crc32_v2::byfour::crc32_little_16;

assert_eq!(crc32_little_16(0, b"123456789"), 0xCBF43926);

let data: Vec<u8> = (0u8..=255).cycle().take(1_048_576).collect();
let crc = crc32_little_16(0, &data);
println!("CRC-32: {crc:#010X}");

ยงcrc32_little_8: Slicing-by-8 (~1 GiB/s)

use crc32_v2::byfour::crc32_little_8;

assert_eq!(crc32_little_8(0, b"123456789"), 0xCBF43926);

ยงcrc32_little: Slicing-by-4 (~833 MiB/s)

use crc32_v2::byfour::crc32_little;

assert_eq!(crc32_little(0, b"123456789"), 0xCBF43926);

ยงcrc32_big: Big-endian (unreflected)

use crc32_v2::byfour::crc32_big;

let empty: &[u8] = &[];
assert_eq!(crc32_big(0, empty), 0);

let full = crc32_big(0, b"Hello, world!");
let chained = crc32_big(crc32_big(0, b"Hello, "), b"world!");
assert_eq!(full, chained);

ยงcrc32_combine: Merge two CRCs in O(log n)

use crc32_v2::{crc32, crc32_combine};

let crc1 = crc32(0, b"Hello, ");
let crc2 = crc32(0, b"world!");
let combined = crc32_combine(crc1, crc2, b"world!".len() as u64);
assert_eq!(combined, crc32(0, b"Hello, world!"));

ยงDigest: Streaming incremental checksum

use crc32_v2::Digest;

let mut digest = Digest::new();
digest.update(b"Hello, ");
digest.update(b"world!");
assert_eq!(digest.finalize(), 0xEBE6C6E6);

let bytes: [u8; 4] = digest.digest();
assert_eq!(u32::from_be_bytes(bytes), 0xEBE6C6E6);

let existing = crc32_v2::crc32(0, b"prefix:");
let mut d = Digest::with_initial(existing);
d.update(b" suffix");
assert_eq!(d.finalize(), crc32_v2::crc32(existing, b" suffix"));

ยง๐Ÿ“– API Complexity Table

MethodTimeNotes
crc32(start, buf)O(n)byte-at-a-time, ~343 MiB/s
crc32_little(start, buf)O(n)slicing-by-4, ~833 MiB/s
crc32_little_8(start, buf)O(n)slicing-by-8, ~1 GiB/s
crc32_little_16(start, buf)O(n)slicing-by-16, ~1.3 GiB/s
crc32_big(start, buf)O(n)big-endian (unreflected)
crc32_combine(c1, c2, len2)O(log n)GF(2) repeated squaring
Digest::new()O(1)
Digest::update(data)O(n)n = data.len()
Digest::finalize()O(1)does not reset
Digest::digest()O(1)returns [u8; 4] (big-endian)
Digest::reset()O(1)

ยง๐Ÿ— Build-time Code Generation: crc32-codegen

The 16 little-endian slicing tables and the big-endian table are generated at compile-time by the crc32-codegen subcrate and written to $OUT_DIR/crc32tables.rs. The main crate includes the generated file via include!().

This pattern (subcrate + build.rs) means that the tables are always consistent with the source, and no generated files are committed to the repository.

ยง๐Ÿ“Š Running Benchmarks

# All benchmark groups
cargo bench --bench benchmark
cargo bench --bench nano_benchmark
cargo bench --bench compare_benchmark

# Quick run
cargo bench -- --quick

Results are written to target/criterion/ as interactive HTML reports. See BENCHMARKS.md for measured throughput numbers.

ยง๐Ÿ”’ Safety

#![forbid(unsafe_code)] is enforced crate-wide. All CRC-32 algorithms (table lookups, slicing loops, GF(2) matrix arithmetic) are pure safe Rust.

ยง๐Ÿ”— See Also

Re-exportsยง

pub use combine::crc32_combine;
pub use digest::Digest;
pub use tables::crc32;

Modulesยง

byfour
Multi-Width CRC-32 Implementations
combine
GF(2) Matrix Arithmetic and CRC Combination
crc32tables
Generated CRC-32 lookup tables, produced by crc32-codegen at build time.
digest
Streaming CRC-32 Digest
nodenode and std
Node.js Bindings
tables
CRC-32 Byte-at-a-Time Table Lookup