Files
skills/docs/foundation/bitpacker/bitpacker-crypto/src/crc32.md
2026-05-29 08:20:56 +01:00

4.7 KiB

CRC32 + Adler32 Checksums

Purpose

Fast non-cryptographic checksums for bit-packed payloads. crc32 implements the IEEE-802.3 / zlib polynomial (0xedb88320); adler32 implements the RFC 1950 algorithm. Both are designed to detect accidental corruption (single-bit flips, wire-level errors, dropped bytes), not adversarial tampering — for cryptographic integrity, use the AEAD or signed-bitschema primitives in @suaveplan/bitpacker-crypto's encrypted/ and signed/ modules.

The four wrappers (appendCrc32, verifyAndStripCrc32, appendAdler32, verifyAndStripAdler32) bookend a payload with a 4-byte big-endian checksum so framed bitpacker output can be transmitted over a noisy channel and integrity-checked at the receiving end. The wrappers throw on truncated input or checksum mismatch; the bare crc32 / adler32 functions return the raw 32-bit value for callers that want to integrate the check elsewhere.

Features

  • crc32(data) — IEEE-802.3 / zlib polynomial CRC32 with a precomputed 256-entry table
  • adler32(data) — RFC 1950 Adler32 with the standard MOD_ADLER = 65521 prime
  • appendCrc32 / appendAdler32 — append 4-byte big-endian checksum
  • verifyAndStripCrc32 / verifyAndStripAdler32 — verify and strip 4-byte checksum, throwing on mismatch or short input
  • Pure JS, no dependencies, deterministic output, browser- and Node-safe

Usage: Basic Example

import { crc32, appendCrc32, verifyAndStripCrc32 } from "@suaveplan/bitpacker-crypto";

const payload = new Uint8Array([1, 2, 3, 4]);
const checksum = crc32(payload);            // 0xb63cfbcd
const framed = appendCrc32(payload);        // 8 bytes: payload + 4-byte CRC
const restored = verifyAndStripCrc32(framed); // -> [1, 2, 3, 4]

Usage: Advanced Example

import {
    appendCrc32,
    verifyAndStripCrc32,
    appendAdler32,
    verifyAndStripAdler32,
} from "@suaveplan/bitpacker-crypto";

// Frame a bit-packed payload, transmit, and validate on receive.
function transmit(payload: Uint8Array): Uint8Array {
    return appendCrc32(payload);
}

function receive(framed: Uint8Array): Uint8Array {
    try {
        return verifyAndStripCrc32(framed);
    } catch (err) {
        // Caller decides: retransmit, drop, or escalate to a higher-level
        // integrity check (signed-bitschema for adversarial channels).
        throw err;
    }
}

// Adler32 is faster but weaker; pick it for short payloads on trusted channels.
const cheap = appendAdler32(new Uint8Array([0xde, 0xad, 0xbe, 0xef]));
const back = verifyAndStripAdler32(cheap);

API Reference

crc32(data: Uint8Array): number

Returns the 32-bit unsigned CRC32 value of data using the IEEE-802.3 / zlib polynomial (0xedb88320). Uses a precomputed 256-entry table for one-byte-per-iteration throughput.

adler32(data: Uint8Array): number

Returns the 32-bit unsigned Adler32 value of data per RFC 1950 (a and b accumulators with MOD_ADLER = 65521).

appendCrc32(data: Uint8Array): Uint8Array

Returns a new array containing data followed by 4 big-endian bytes of crc32(data).

verifyAndStripCrc32(data: Uint8Array): Uint8Array

Returns the leading data.length - 4 bytes if the trailing 4 bytes match crc32(payload). Throws Error with "Data too short for CRC32 verification" if data.length < 4, or "CRC32 mismatch: expected X, got Y" on mismatch.

appendAdler32(data: Uint8Array): Uint8Array

Returns a new array containing data followed by 4 big-endian bytes of adler32(data).

verifyAndStripAdler32(data: Uint8Array): Uint8Array

Mirrors verifyAndStripCrc32 for Adler32. Same error semantics.

Implementation Notes

  • CRC32 polynomial = 0xedb88320. This is the bit-reversed form of the standard IEEE-802.3 polynomial (0x04c11db7). The reversal is encoded in the table-precomputation loop (c & 1 ? POLY ^ (c >>> 1) : c >>> 1) so the streaming inner loop processes least-significant bits first, matching zlib / gzip / PNG.
  • Big-endian checksum framing. Both append wrappers write the 32-bit checksum as big-endian bytes, matching network byte order. The verifyAndStrip counterparts read with getUint32(offset, false) (false = big-endian).
  • Not cryptographically secure. A motivated attacker can construct collisions for both CRC32 and Adler32 in O(1). Use these for accidental-corruption detection only; use AEAD or signature primitives elsewhere in @suaveplan/bitpacker-crypto for adversarial integrity.
  • No allocation in the hot path. crc32 / adler32 only allocate via the precomputed CRC32_TABLE. appendCrc32 / appendAdler32 allocate one output buffer; verifyAndStripCrc32 / verifyAndStripAdler32 allocate via slice for the returned payload.