networking · intermediate · ~25 min

Compute CRC-8 over a byte stream (poly 0x07)

Bit-by-bit polynomial division — the heart of every CRC.

Challenge

Compute the CRC-8 (polynomial 0x07, initial value 0x00, no XOR-out) of a byte stream:

unsigned char crc8(const unsigned char *data, size_t len);

The algorithm:

  1. crc = 0.
  2. For each byte b in data:
    • crc ^= b.
    • Repeat 8 times: if the high bit of crc is set, crc = (crc << 1) ^ 0x07; else crc = crc << 1. Mask to 8 bits if needed.
  3. Return crc.

Examples

crc8("123456789", 9)          -> 0xF4
crc8("", 0)                   -> 0x00
crc8("\x01", 1)              -> 0x07
crc8("A", 1)                  -> 0xC0     // (one byte 'A' = 0x41)

Why this matters

Every 1-Wire temperature sensor, every USB Power Delivery negotiator, and many CAN bus frames carry a CRC-8 that you can compute yourself with this exact loop. Real systems use lookup tables for speed — but the loop form is the reference you compare against.

Why this matters

CRC checksums are everywhere: 1-Wire / I²C / CAN / SMBus all use CRC-8, and TCP/Ethernet use larger CRCs with the same core algorithm. Writing one by hand demystifies what looks like a magic value in protocol specs.

Input format

Byte buffer + length.

Output format

The CRC-8 byte.

Constraints

No lookup tables; bit-by-bit loop.

Starter code

#include <stddef.h>
unsigned char crc8(const unsigned char *data, size_t len) { /* TODO */ return 0; }

Common mistakes

Forgetting to mask crc back to 8 bits after the shift. Using the wrong polynomial. Initialising with 0xFF (some CRC-8 variants do; this one uses 0x00).

Edge cases to handle

Empty buffer → 0; single byte; ASCII string "123456789" is the canonical check value (0xF4).

Complexity

O(8 * len).

Background lessons

Up next

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.