Spec & internals
QR code checksum and integrity
A QR code carries no payload checksum. Reed–Solomon protects codewords against damage, and BCH codes protect the 15-bit format and 18-bit version fields, but a code that decodes cleanly proves nothing about who made it. Integrity and authenticity must live in the payload — a CRC, a token or a signature.
What protection a QR code actually contains
Three error-control mechanisms exist in the symbol, protecting three different things:
| Mechanism | Protects | Size |
|---|---|---|
| Reed–Solomon | data + EC codewords | 7–30% of codewords, by level |
| BCH (15,5) | format information — EC level and mask | 10 check bits on 5 data bits, stored twice |
| BCH (18,6) | version information (versions 7+) | 12 check bits on 6 data bits, stored twice |
Notice what is missing: there is no checksum, CRC or hash over the payload itself. The bit stream is mode indicators, character counts, data and padding — nothing that summarises or fingerprints the content. QR's error control exists to survive transport damage (dirt, blur, missing modules), not to vouch for the data.
What Reed–Solomon does and does not guarantee
What it does: if the damaged codewords are within the level's budget, the decoder recovers the original codewords exactly — error correction is reconstruction, not approximation. As a side effect it provides strong error detection: random corruption beyond the correctable budget almost always fails to decode rather than producing wrong text, because a fabricated-but-consistent codeword set is astronomically unlikely to arise by accident. Silent misdecodes are possible in principle when damage grossly exceeds the budget, which is one reason critical systems re-verify decoded content rather than trusting a lone scan.
What it does not do:
- Authenticate. Reed–Solomon math is public and runs in every generator. Anyone can produce a flawlessly valid QR code saying anything — that is precisely what a quishing sticker is. "It scanned cleanly" carries zero evidence about who created it.
- Validate meaning. A decoder happily returns a malformed URL, a wrong account number or an expired link. Correct transport of wrong content is still wrong content.
- Protect the payload's semantics. A typo in the URL you encoded is preserved with perfect fidelity.
If you need integrity, put it in the payload
Since the symbol layer will not carry it, the payload layer must. Three escalating patterns, all in production use:
- Checksums for typos and truncation. EMVCo payment payloads — the format behind PIX — end in a mandatory CRC-16 over the whole string, so a mis-scanned or hand-mangled payload fails validation in the payment app (details: PIX CRC16 checksum). Same idea: check digits in GS1 GTINs.
- Server-side validation for guessing resistance. Ticketing and voucher codes embed a random token that the backend validates — no offline forgery value, revocable, but requires connectivity.
- Signatures for authenticity. A cryptographic signature over the payload proves origin offline — anyone can verify with the public key, only the key holder can issue. Formats and trade-offs: signed QR codes and authenticity.
The pattern to internalise: the QR layer is a transport; trust decisions belong to the content. Scanner-side, the same logic applies to humans — check what a code decodes to before acting on it.
Generator-side, the useful integrity check is the round trip: render the code, decode it,
compare against the intended payload byte for byte. That is exactly what
/validate automates, and what UseQR's /api/v1/verify endpoint exposes for
pipelines.
FAQ
Does a QR code have a built-in checksum?
Not over the payload. Reed–Solomon codewords protect against physical damage and BCH codes protect the small format and version fields, but nothing in the symbol fingerprints or validates the data content itself.
Can a QR code decode to the wrong text?
Physically corrupted codes overwhelmingly fail to decode rather than misdecode, because consistent-but-wrong codeword sets rarely occur by chance. The realistic risk is different — a perfectly valid code that was malicious or mistyped from the start.
How do payment QR codes prevent errors?
The payload format adds its own protection. EMVCo-derived formats such as PIX end with a mandatory CRC-16 the payment app must verify, and account identifiers often carry check digits, so mangled payloads are rejected before money moves.
How do I make a QR code tamper-evident?
You cannot at the symbol level — anyone can print a valid code. Embed a server-validated token or a cryptographic signature in the payload, or control the physical medium with tamper-evident labels, and verify scans against the issuing system.
Try it — free, no signup
Related
- QR code anatomy — every region of the symbol — A labelled tour of a QR code: finder patterns, separators, timing, alignment, format and version information, the data region and the quiet zone.
- Reed–Solomon error correction in QR codes, made readable — QR codes append Reed–Solomon check codewords computed over GF(256). What "recovers 30% damage" really means: erasures count once, unknown errors twice.
- Format information — the 15 bits everything depends on — Format information encodes the EC level and mask in 5 bits, protects them with BCH(15,5), XORs with a fixed mask, and is written twice beside the finders.
- Signed QR codes and authenticity — How signed QR codes prove who issued a code and that it was not altered — the JWS pattern, the EU Digital COVID Certificate, SQRC, and a build sketch.