Skip to main content

Verified CRC source-code for C, C#, Go, Python, Rust, TypeScript, Verilog, and VHDL — catalogue-driven, typed introspection API, self-test embedded.

Project description

crcglot

tests coverage ruff ty

Verified CRC source code for C / C++ ⚙️, Rust 🦀, Go 🚦, C# 💠, Python 🐍, TypeScript 🔷, Verilog 🔧, and VHDL 🔌. Catalogue-driven, self-test embedded, multi-language by design. Pure-stdlib package — zero runtime dependencies.

LLMs will gladly write you CRC code. It might even be right. crcglot guarantees the generated code matches the canonical reveng catalogue test vector (crc("123456789") == <check value>) and ships a self-test you can run on your toolchain to prove it.

Quick start

uv tool install crcglot         # or: pip install crcglot
crcglot c crc32 file=mycrc

That's it. You now have mycrc.h and mycrc.c — drop-in CRC-32 with a built-in _self_test() you can call to verify it matches the canonical reveng check value.

The whole model is three choices: which algorithm (crc32, crc16-modbus, … — crcglot list for all 71), which language (c / python / rust / vhdl / verilog / go / csharp / typescript), and whether you want it --small (smallest code, the default) or --fast (fastest the target supports). crcglot figures out the implementation details — you never have to know what "slice-by-8" is.

crcglot rust crc32 --fast file=mycrc     # fastest Rust crc32
crcglot c crc8 --small                    # smallest C crc8, to stdout

Installation

Tool Command Use when
uv (recommended) uv tool install crcglot You just want the crcglot CLI on PATH. Isolated install, no global pollution.
uv (as a library) uv add crcglot You're calling the generators from Python (e.g. a build script that emits CRC code into your repo).
pip pip install crcglot You don't have uv. Identical package, slower install.
pipx pipx install crcglot Same isolation story as uv tool, if pipx is what you have.

Python 3.11+, no other runtime dependencies — crcglot itself is pure stdlib. Per-target toolchains (gcc, rustc, tsx, iverilog, etc.) only matter if you want to run the generated code; the generator produces source either way.

Or use it from Python code:

from crcglot import LANGUAGES
header, source = LANGUAGES["c"].generator("crc32")

Both surfaces are documented in detail below.

What you get per language

Function Purpose
<fname>_init / _update / _finalize Streaming triple — feed data chunk by chunk
<fname> One-shot wrapper that calls the streaming triple
<fname>_self_test Verify against the reveng check value on your toolchain

Every target ships a runtime-callable _self_test(): C returns 0/1; Rust / Go / C# / TypeScript / Python / Verilog / VHDL return bool / boolean / bit. No #[cfg(test)] gating — call it from your release build, a boot self-check, or a startup assertion.

How it's verified

CI runs the Python-level suite on every push: every algorithm in the reveng catalogue is checked against its hardcoded canonical check value — not the catalogue's own check field, so a silent regression in the engine can't hide — and the Python generator is run end-to-end (generated, exec'd, and called on b"123456789") against the same hardcoded vectors. The slow tier on top of that compiles and executes the generated source for every algorithm in C, Rust, Go, C#, TypeScript, Verilog, and VHDL via gcc / rustc / go / dotnet / tsx (Node) / iverilog / ghdl and re-checks the runtime result — same algorithm coverage, exercised through each real toolchain.

Every generated file also ships its own _self_test() carrying that same canonical vector. For every target except Python, you should call _self_test() once in your build environment — wire it into a unit test, a startup assertion, or your boot self-check. Our CI proves the generator emits correct code on our reference toolchain; only running _self_test() on yours proves your compiler version, optimization flags, target endianness, and integer widths haven't introduced a subtle disagreement. Python is the exception: the interpreter that ran the CI suite is the one running your code, so the in-environment check would be redundant.

CLI reference

crcglot <command> [options...]

crcglot list [GLOB]

Browse the catalogue. Optional GLOB filters by shell-style pattern (e.g. crc16-*). Exit code 1 if nothing matches.

crcglot list                # all 71 algorithms
crcglot list 'crc32-*'      # just the CRC-32 family

crcglot info <name>

Print parameters (width, poly, init, refin, refout, xorout, check, desc) for one algorithm. Exit 1 on unknown name.

crcglot info crc64-xz

crcglot {c | csharp | go | python | rust | typescript | verilog | vhdl} <algorithm> [options...] [tokens...]

Generate source code for the chosen target language. Pick your intent — crcglot picks the implementation:

Option / token Effect
--small Smallest code, zero RAM table (bit-by-bit). The default — works for any width.
--fast Fastest the target supports: slice-by-8 for width 32/64 on compiled targets, table-driven otherwise.
--custom Use raw Rocksoft/Williams params instead of a catalogue lookup (see below).
file=STEM Write to disk (extension picked per language; see below). Omit for stdout.
symbol=NAME Override the emitted function name. Default: derived from algorithm, or from file=STEM if given.

File extensions per language: C emits STEM.h + STEM.c; Python .py; Rust .rs; VHDL .vhd; Verilog .sv (SystemVerilog 2012); Go .go; C# .cs; TypeScript .ts.

Expert overrides (you usually don't need these — --fast chooses for you): --table forces the 256-entry single-table form, and --slice8 forces the 8-table form. They exist for the rare case where you want the middle of the size/speed curve explicitly — e.g. a RAM-constrained target where the 1 KiB table is fine but slice-by-8's 8 KiB isn't. --slice8 is CRC-32/64 + compiled targets only.

Rules:

  • The variant selectors --small / --fast / --table / --slice8 are mutually exclusive — pick at most one (exit 2 otherwise). No selector = --small.
  • --slice8 python silently falls back to --table (CPython's per-int overhead eats the slice-by-8 speedup; stderr warns). --fast never needs this fallback — it only picks slice-by-8 where it actually applies.
  • Without file=, output goes to stdout. For C, header is emitted first, then source.
  • C / Rust / VHDL files embed <symbol>_self_test() returning 0 on success. In constrained embedded targets, standard toolchain flags (-Wl,--gc-sections for C, LTO for Rust) strip whatever you don't call.

--custom (raw Rocksoft/Williams parameters)

For algorithms not in the catalogue:

crcglot c --custom width=16 poly=0x1234 init=0xFFFF \
         refin=true refout=true xorout=0x0000 file=mycustom
Param Required Notes
width=N yes 8, 16, 32, or 64 only
poly=X yes Hex (0x...) or decimal
init=X no Default 0. Hex or decimal.
refin=B no Default false. Accepts true/false/1/0/yes/no/on/off.
refout=B no Default false. Same boolean syntax.
xorout=X no Default 0.
name=NAME no Default crc_custom. Used in generated comments.
desc=TEXT no Free-form description in comments.

The check value for the custom parameters is computed automatically (generic_crc(b"123456789", ...)) and embedded into the generated _self_test().

Catalogue

64+ algorithms covering everything from CRC-8 (ATM, AUTOSAR, Bluetooth, Maxim 1-Wire) through CRC-16 (Modbus, XMODEM, CCITT, IBM SDLC) through CRC-32 (Ethernet, bzip2, iSCSI, AUTOSAR) to CRC-64 (XZ, ECMA-182, NVMe, Redis). Browse with crcglot list.

Programmatic API

Two registries, both keyed by short code:

LANGUAGES — supported target languages

from crcglot import LANGUAGES

for code, info in LANGUAGES.items():
    print(f"{info.emoji} {info.display_name:<10}  {info.extensions}  "
          f"{sorted(info.variants)}")
    # → ⚙️ C / C++       ('.h', '.c')  ['bitwise', 'slice8', 'table']
    # → 💠 C#            ('.cs',)      ['bitwise', 'slice8', 'table']
    # → 🚦 Go            ('.go',)      ['bitwise', 'slice8', 'table']
    # → 🐍 Python        ('.py',)      ['bitwise', 'table']
    # → 🦀 Rust          ('.rs',)      ['bitwise', 'slice8', 'table']
    # → 🔷 TypeScript    ('.ts',)      ['bitwise', 'slice8', 'table']
    # → 🔧 Verilog       ('.sv',)      ['bitwise']
    # → 🔌 VHDL          ('.vhd',)     ['bitwise']

Each entry is a frozen LanguageInfo dataclass with:

  • code — dispatch key ("c", "csharp", ..., "typescript", "verilog")
  • extensions — file extension tuple ((".h", ".c") for C; single-element for the rest)
  • variants — subset of {"bitwise", "table", "slice8"} that the generator accepts
  • generator(name, ...) — name-lookup callable (returns source string, or (header, source) tuple for C)
  • generator_from_entry(name, algo, ...) — bypass the catalogue with a custom AlgorithmInfo
  • emoji — single-grapheme pictographic identifier for terminals / docs
  • display_name — human-readable name (e.g. "C / C++", "TypeScript") — distinct from code

ALGORITHMS — the reveng CRC catalogue

from crcglot import ALGORITHMS

modbus = ALGORITHMS["crc16-modbus"]
print(modbus.width, hex(modbus.check), modbus.desc)
# → 16 0x4b37 Modbus RTU serial protocol

# Filter to CRC-32 only.
crc32_family = [a for a in ALGORITHMS.values() if a.width == 32]

Each entry is a frozen AlgorithmInfo dataclass with the full Rocksoft / Williams parameter set: name, width, poly, init, refin, refout, xorout, check, desc.

Custom polynomials

from crcglot import AlgorithmInfo, LANGUAGES, generic_crc

# Compute the canonical check value for a custom poly.
check = generic_crc(b"123456789", 16, 0x1234, 0xFFFF, True, True, 0x0000)

# Build an AlgorithmInfo and feed it to any generator.
algo = AlgorithmInfo(
    name="my_crc16", width=16, poly=0x1234, init=0xFFFF,
    refin=True, refout=True, xorout=0x0000, check=check,
    desc="My custom CRC-16",
)
code = LANGUAGES["rust"].generator_from_entry("my_crc16", algo, table=True)

Fast runtime CRC (optional C extension)

Beyond generating code, crcglot can compute CRCs at runtime — and it's fast.

Performance, stated honestly: with the C extension, crcglot computes any of the 71 CRCs from Python at compiled-C-class throughput on bulk data (~1.7 GB/s on a 1 MiB buffer — on par with generated C and ahead of generated Rust), and for IEEE CRC-32 / JAMCRC it delegates to the stdlib's hardware path (~tens of GB/s), faster than the generated code. The pure-Python fallback always works but is ~1000× slower. Two caveats: the "compiled-class" numbers need the extension installed (the wheel / crcglot[fast]), and they hold for bulk/streaming data — many tiny one-shot calls pay Python↔C overhead per call (use the batch API for those). All figures are platform-specific; see BENCHMARKS.md.

At runtime there's no variant choice to make — the same philosophy as --small/--fast on the generator, taken all the way: you just call crcglot.generic_crc(data, width, poly, init, refin, refout, xorout) and it picks the fastest path available on your machine. There's no table=/slice8= knob here; the speed you get depends only on whether the C extension is installed.

Under the hood it dispatches three ways (you never select among them):

  1. IEEE CRC-32 / JAMCRC → stdlib zlib.crc32 (hardware CRC folding — PCLMULQDQ on x86, PMULL / crc32 instructions on ARM): tens of GB/s. No software CRC out-runs silicon, so crcglot borrows the stdlib's path for the algorithms it covers.
  2. Everything else → the optional C extension (crcglot._c, slice-by-8 / table-driven): ~1-2 GB/s, ~2,000× over pure Python.
  3. No extension built → pure Python: always works, just slow.

The extension ships in the prebuilt wheels (pip install crcglot gets it on common platforms). To force it / pull the build deps explicitly:

uv tool install "crcglot[fast]"     # or: pip install "crcglot[fast]"

It's a single abi3 wheel per platform (CPython 3.11+), and crcglot stays fully functional in pure Python if no wheel matches your platform.

from crcglot import generic_crc

# One-shot.  crc32 here rides the zlib hardware path automatically.
crc = generic_crc(b"123456789", 32, 0x04C11DB7, 0xFFFFFFFF, True, True, 0xFFFFFFFF)

Streaming and batch (C extension)

For chunked data and high-volume small-buffer workloads, the extension exposes two more shapes:

from crcglot import _c   # present iff the extension is installed

# Streaming -- bind the algorithm once, feed chunks, digest on demand
# (hashlib idiom: update / digest / reset / copy).
s = _c.CrcStream(width=32, poly=0x04C11DB7, init=0xFFFFFFFF,
                 refin=True, refout=True, xorout=0xFFFFFFFF)
for chunk in stream:
    s.update(chunk)
result = s.digest()

# Batch -- CRC many buffers, paying the Python↔C transition once
# (the win for framed protocols / packet streams).
results = _c.c_crc_many(list_of_packets, 32, 0x04C11DB7, 0xFFFFFFFF,
                        True, True, 0xFFFFFFFF)

See BENCHMARKS.md for measured throughput of each runtime path against the generated-code gallery.

Example output

See EXAMPLES.md for the actual generated source for crc32 across every language × implementation combination (C / Rust / Python / VHDL / Verilog / Go / C# / TypeScript crossed with bit-by-bit, table-driven, and slice-by-8 where supported). Every block is reproducible with one CLI command.

Benchmarks

See BENCHMARKS.md for measured crc32 throughput across every (language × variant) cell at 1 KiB and 1 MiB. Within each language the trend is monotonic (bit-by-bit < table < slice-by-8) but the absolute speedup at each step depends heavily on how well the compiler optimizes the baseline — Rust's LLVM-vectorized bit-by-bit nearly ties its table-driven, while C# / Python see a 10×+ jump just from table-driven because their bitwise loops aren't vectorized. VHDL and Verilog are excluded: they're simulator references for hardware datapaths, not software runtime.

Acknowledgments

CRC catalogue data is derived from Greg Cook's reveng project — the canonical source for CRC algorithm parameters since 1999.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

crcglot-0.8.0.tar.gz (99.0 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

crcglot-0.8.0-cp311-abi3-win_arm64.whl (79.2 kB view details)

Uploaded CPython 3.11+Windows ARM64

crcglot-0.8.0-cp311-abi3-win_amd64.whl (80.8 kB view details)

Uploaded CPython 3.11+Windows x86-64

crcglot-0.8.0-cp311-abi3-musllinux_1_2_x86_64.whl (96.9 kB view details)

Uploaded CPython 3.11+musllinux: musl 1.2+ x86-64

crcglot-0.8.0-cp311-abi3-musllinux_1_2_aarch64.whl (96.7 kB view details)

Uploaded CPython 3.11+musllinux: musl 1.2+ ARM64

crcglot-0.8.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (96.6 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ ARM64

crcglot-0.8.0-cp311-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (96.9 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

crcglot-0.8.0-cp311-abi3-macosx_11_0_arm64.whl (77.8 kB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

File details

Details for the file crcglot-0.8.0.tar.gz.

File metadata

  • Download URL: crcglot-0.8.0.tar.gz
  • Upload date:
  • Size: 99.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for crcglot-0.8.0.tar.gz
Algorithm Hash digest
SHA256 d68e9978f89234e267148796b881b2114d933c6dcf6037f55e37a94f1ee37eec
MD5 6185716ebca5e6ea6aef901ed3d758af
BLAKE2b-256 2a73bbd02f4d46d8a48d531b934928241b96e23d998f6ca8ca0128e91062356c

See more details on using hashes here.

Provenance

The following attestation bundles were made for crcglot-0.8.0.tar.gz:

Publisher: wheels.yml on hucker/crcglot

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file crcglot-0.8.0-cp311-abi3-win_arm64.whl.

File metadata

  • Download URL: crcglot-0.8.0-cp311-abi3-win_arm64.whl
  • Upload date:
  • Size: 79.2 kB
  • Tags: CPython 3.11+, Windows ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for crcglot-0.8.0-cp311-abi3-win_arm64.whl
Algorithm Hash digest
SHA256 20d2c892f96c7ff21cd4786fdcd7fd0cb1edfd0486433371b2795d9c5abc014e
MD5 b614764f898d0a17863fe1772fca074f
BLAKE2b-256 85b91ff8fc39c9f292d97feceb9fe16ef26ec6bc08b713fdfbfd2b1d47b3b437

See more details on using hashes here.

Provenance

The following attestation bundles were made for crcglot-0.8.0-cp311-abi3-win_arm64.whl:

Publisher: wheels.yml on hucker/crcglot

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file crcglot-0.8.0-cp311-abi3-win_amd64.whl.

File metadata

  • Download URL: crcglot-0.8.0-cp311-abi3-win_amd64.whl
  • Upload date:
  • Size: 80.8 kB
  • Tags: CPython 3.11+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for crcglot-0.8.0-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 8f2d30bd5877cdbe34e76a88537288a26a8dae3f6e87b2e66b6d0da4fc5884bd
MD5 979e549a3cc5ccd55b7c07cc169e8c52
BLAKE2b-256 e20b695a88ae019d766e505acef4b0c6dcc413fdd99b83f08900c90ec1f79eb0

See more details on using hashes here.

Provenance

The following attestation bundles were made for crcglot-0.8.0-cp311-abi3-win_amd64.whl:

Publisher: wheels.yml on hucker/crcglot

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file crcglot-0.8.0-cp311-abi3-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for crcglot-0.8.0-cp311-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 7926fc5deb4e58644af9d4fb51053a379c43819c0c303b73894e758d6645e419
MD5 e8887f988925b7199a494b23a2d21110
BLAKE2b-256 49c01c8c846e6ea29553bc017f26e9bd18382abd2807ad35466d1e084864b7c9

See more details on using hashes here.

Provenance

The following attestation bundles were made for crcglot-0.8.0-cp311-abi3-musllinux_1_2_x86_64.whl:

Publisher: wheels.yml on hucker/crcglot

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file crcglot-0.8.0-cp311-abi3-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for crcglot-0.8.0-cp311-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 3c8e19a72828af5df5ed5b34cf0f746612536159f9878b157cb47de8099ec1a1
MD5 74410a4ee57832bf6f00c3255d149b3f
BLAKE2b-256 94b6bc03ccb334c067ac16e8e52c0d6c20aef66c2f1984542a5161b7ad920e94

See more details on using hashes here.

Provenance

The following attestation bundles were made for crcglot-0.8.0-cp311-abi3-musllinux_1_2_aarch64.whl:

Publisher: wheels.yml on hucker/crcglot

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file crcglot-0.8.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for crcglot-0.8.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 69d2e944a1a85da6339e363bff803a237f56896b7f59c49570e302d67155be71
MD5 775433a2b8a51446583a33baf4e9965d
BLAKE2b-256 d738b07455c2f3833fc556d9952c37b934827950e8bf4b53996c54926ac912ab

See more details on using hashes here.

Provenance

The following attestation bundles were made for crcglot-0.8.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: wheels.yml on hucker/crcglot

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file crcglot-0.8.0-cp311-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for crcglot-0.8.0-cp311-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 662859753843106ead24893849f12f68b700db2c14114a646e0210cb15713611
MD5 c2843e66ac20a7b01b0de5b537c583b9
BLAKE2b-256 a68de121c9e19af785da57e187fcc6301f9c18d9463acb47bc3ac1ebe413a0c7

See more details on using hashes here.

Provenance

The following attestation bundles were made for crcglot-0.8.0-cp311-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: wheels.yml on hucker/crcglot

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file crcglot-0.8.0-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for crcglot-0.8.0-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 b880658c1ba4c99646d1830d002db17de1c037fe808d514317effc7c4ed78e21
MD5 9afed80442ac7bb90ff681cacc2df67f
BLAKE2b-256 839bbf233f9f36ce3684c0455b7bcec510607b47bd0049b8d214d14a2689867c

See more details on using hashes here.

Provenance

The following attestation bundles were made for crcglot-0.8.0-cp311-abi3-macosx_11_0_arm64.whl:

Publisher: wheels.yml on hucker/crcglot

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page