Documents · · 3 min read
MRZ check digits, explained
How the 7-3-1 algorithm in ICAO Doc 9303 works, worked through on the specimen passport, and what it can and cannot prove.
The two or three lines of <-filled text at the bottom of a passport or ID card are the machine-readable zone (MRZ), defined by ICAO Doc 9303. They repeat the key fields of the document in a fixed layout and a restricted alphabet, and protect the important ones with check digits. Recomputing those digits is the first thing a document check should do.
The layouts
| Format | Lines × characters | Used on |
|---|---|---|
| TD1 | 3 × 30 | ID cards, residence permits |
| TD2 | 2 × 36 | Older ID cards, some permits |
| TD3 | 2 × 44 | Passports |
| MRV-A | 2 × 44 | Visas, full-page |
| MRV-B | 2 × 36 | Visas, smaller |
KYCVerify's parser supports all five, plus the French national ID card (2 × 36, IDFRA), which predates the TD formats and has no expiry date in its MRZ.
The algorithm
- Give every character a value: digits are themselves,
A-Zare 10 to 35, and the filler<is 0. - Multiply each value by a repeating weight of 7, 3, 1, 7, 3, 1, … from the left.
- Add the products and take the remainder modulo 10. That is the check digit.
Worked example
ICAO's specimen passport, issued by the fictional state of Utopia (UTO), has this second line:
L898902C36UTO7408122F1204159ZE184226B<<<<<10P<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<
L898902C36UTO7408122F1204159ZE184226B<<<<<10
- 1-9 Document number
- L898902C3
- 10 Its check digit
- 6
- 14-19 · 20 Birth date · check
- 740812 · 2
- 22-27 · 28 Expiry · check
- 120415 · 9
- 11-13 Nationality
- UTO
- 21 Sex
- F
- 29-42 · 43 Optional · check
- ZE184226B · 1
- 44 Composite check
- 0
The document number is L898902C3, followed by its check digit 6:
| Character | L | 8 | 9 | 8 | 9 | 0 | 2 | C | 3 |
|---|---|---|---|---|---|---|---|---|---|
| Value | 21 | 8 | 9 | 8 | 9 | 0 | 2 | 12 | 3 |
| Weight | 7 | 3 | 1 | 7 | 3 | 1 | 7 | 3 | 1 |
| Product | 147 | 24 | 9 | 56 | 27 | 0 | 14 | 36 | 3 |
The products sum to 316, and 316 mod 10 = 6, which matches. The date of birth 740812 gives 49 + 12 + 0 + 56 + 3 + 2 = 122, check digit 2. The expiry 120415 gives 7 + 6 + 0 + 28 + 3 + 5 = 49, check digit 9. Both match the line.
The composite digit
The last character, 0, is a check digit over the document number, the date of birth, the expiry and the optional data including their own check digits. It catches an edit that was carefully paired with a recomputed field digit, and a swap of whole fields.
OCR and the alphabet
Cameras and OCR confuse 0 and O, 1 and I, 5 and S, 8 and B. Because each MRZ position has a known alphabet (a date is digits, a country code is letters), many of these can be corrected safely. KYCVerify corrects only in typed positions, and reports every correction as (line, column, from, to) so a reviewer can tell a clean read from a repaired one.
Document numbers mix letters and digits, so the type of a position is not known. When a confusion there makes the check digit fail, the parser tries the other readings of the confusable characters that are out of type with their neighbours, and applies one only if it is the single fewest-change reading that makes both the field's and the composite check digit verify.
Long document numbers
TD1 and TD2 have nine positions for the document number. When a number is longer, the ninth position holds <, the remainder continues in the optional-data field, and the check digit after it covers the full number. The parser handles this continuation.
What check digits prove
- They prove the MRZ is internally consistent: it was read correctly and was not edited carelessly.
- They do not prove the document is genuine. Anyone can compute a valid check digit; the algorithm is public.
- That is why a document check also compares the MRZ with the declared type and country, enforces expiry, gates on image quality, and why liveness and face match tie the document to a present person.
Try it with POST /v1/checks/mrz and the two specimen lines: every check digit verifies, and the document expired in 2012.