CRC
A Cyclic Redundancy Check (CRC) is a checksum algorithm used to detect
accidental corruption in binary data. ribs_binary provides a pure-Dart
implementation that covers the full range of standard CRC widths, from 3-bit up
to 82-bit, parametrised by the five values that uniquely define a CRC algorithm:
polynomial, initial register value, input reflection, output reflection, and
final XOR mask.
Standard checksums
The most common widths are available as one-liner getters on Crc. Each
accepts a BitVector — convert a ByteVector with .bits — and returns a
BitVector containing the checksum:
// All CRC specifications define their expected output on ASCII "123456789",
// which makes a convenient sanity-check value.
final data = ByteVector('123456789'.codeUnits).bits;
// One-liner getters for the four standard widths
final crc8Result = Crc.crc8(data); // 0xf4
final crc16Result = Crc.crc16(data); // 0xbb3d
final crc24Result = Crc.crc24(data); // 0x21cf02
final crc32Result = Crc.crc32(data); // 0xcbf43926
// The result is a BitVector; convert to hex for display or to bytes for a packet
void showResult() {
print(crc32Result.toHex()); // cbf43926
// Append a 4-byte CRC-32 checksum to a payload
final payload = ByteVector.fromValidHex('deadbeef');
final checksum = Crc.crc32(payload.bits).bytes;
final packet = payload.concat(checksum); // 8 bytes total
}
Named presets and custom parameters
CrcParams collects presets for the algorithms most commonly found in
specifications and hardware:
| Factory | Algorithm |
|---|---|
CrcParams.crc8() / crc8SMBus() | CRC-8/SMBus |
CrcParams.crc8Rohc() | CRC-8/ROHC |
CrcParams.crc16() / crc16Arc() | CRC-16/ARC |
CrcParams.crc16Kermit() | CRC-16/KERMIT |
CrcParams.crc24() / crc24OpenPgp() | CRC-24/OpenPGP |
CrcParams.crc32() / crc32IsoHdlc() | CRC-32/ISO-HDLC (Ethernet, ZIP) |
Pass a preset to Crc.from() to get a reusable function, or supply the five
parameters directly to Crc.of() for an algorithm not covered by the presets:
// Named presets give access to the full catalogue of standard CRC algorithms.
// Crc.from(CrcParams) turns a preset into a reusable Function1<BitVector, BitVector>.
final kermit16 = Crc.from(CrcParams.crc16Kermit()); // CRC-16/KERMIT
final openPgp24 = Crc.from(CrcParams.crc24OpenPgp()); // CRC-24/OpenPGP
final hdlc32 = Crc.from(CrcParams.crc32IsoHdlc()); // CRC-32/ISO-HDLC
// For algorithms not in CrcParams, supply all five parameters directly:
// poly, initial, reflectInput, reflectOutput, finalXor
final ccitt16 = Crc.of(
BitVector.fromValidHex('1021'), // polynomial
BitVector.fromValidHex('ffff'), // initial register value
false, // do not reflect input bytes
false, // do not reflect output
BitVector.fromValidHex('0000'), // final XOR mask
);
void showCustom() {
print(ccitt16(ByteVector.fromValidHex('12345670').bits).toHex()); // b1e4
}
Incremental computation with CrcBuilder
Crc.builder() returns a CrcBuilder<BitVector> that accumulates state across
multiple updated() calls. This is useful when data arrives in chunks — for
example during a streaming file read or network receive — without needing to
buffer the whole message before computing the checksum.
mapResult() transforms the final BitVector to any other type (such as a
Dart int) in a single step:
// CrcBuilder enables incremental computation: feed data in chunks and call
// result() once at the end. Use this when data arrives in pieces (e.g. from
// a streaming read) without buffering the full message.
final crc32Builder = Crc.builder(
BitVector.fromValidHex('04c11db7'), // CRC-32 polynomial
BitVector.fromValidHex('ffffffff'), // initial value
true, // reflect input
true, // reflect output
BitVector.fromValidHex('ffffffff'), // final XOR
);
void showIncremental() {
final header = ByteVector('HEAD'.codeUnits).bits;
final body = ByteVector('BODY'.codeUnits).bits;
final checksum =
crc32Builder
.updated(header) // feed first chunk
.updated(body) // feed second chunk
.result(); // finalise
print(checksum.toHex());
// mapResult converts the BitVector result to any other type inline
final asInt = crc32Builder.updated(header).updated(body).mapResult((bv) => bv.toInt()).result();
print(asInt); // same checksum as a Dart int
}
CrcBuilder is immutable: each updated() call returns a new builder with the
accumulated state, leaving the original unchanged. This means the same base
builder can be reused across multiple independent computations.