The Verhoeff Algorithm, Explained

The checksum behind every Aadhaar number: what it is, why UIDAI picked it, the tables, a worked example, and a calculator that shows every step.

Interactive Verhoeff calculator

Two answers appear: whether the number as typed passes the check, and what check digit would be appended to it. Computed locally.

What the Verhoeff algorithm is

The Verhoeff algorithm is a check digit scheme: given a number, it computes one extra digit that is appended to the end. Later, anyone who receives the full number can run the same calculation and confirm the check digit still matches. If a digit was mistyped or two neighbouring digits were swapped, the check fails.

It was published in 1969 by the Dutch mathematician Jacobus Verhoeff, who studied real transcription errors made by Dutch postal workers and designed a scheme that catches the ones people actually make. It was the first decimal check digit algorithm to detect all single-digit errors and all adjacent transpositions using just one check digit.

In India, the Unique Identification Authority of India (UIDAI) uses Verhoeff for the 12th digit of every Aadhaar number and the 16th digit of every Aadhaar Virtual ID.

Why UIDAI chose Verhoeff over Luhn

The better-known Luhn algorithm (used by credit cards) is simpler but weaker. The table below compares the error types each scheme catches. Verhoeff's strength comes from using a non-commutative operation — the order in which digits are combined matters, which is exactly what you need to detect swapped digits.

Error typeExampleLuhnVerhoeffDamm
Single digit wrong5 → 6100%100%100%
Adjacent digits swapped12 → 21Misses 09 ↔ 90100%100%
Twin errors11 → 22Misses some~95%~95%
Jump transposition123 → 321No~94%~94%
Phonetic (1x ↔ x0)13 → 30No~95%~95%

Percentages are the approximate share of errors of that type that are detected.

The three tables

Verhoeff works with three lookup tables. You never need to understand the group theory to implement it — you just index into these tables.

Multiplication table d (dihedral group D5)

Combines the running value with the next digit. Notice it is not symmetric: d[1][2] is 3 but d[2][1] is 3 too, whereas d[1][5] is 6 and d[5][1] is 9. That asymmetry is what detects swaps.

d0123456789
00123456789
11234067895
22340178956
33401289567
44012395678
55987604321
66598710432
77659821043
88765932104
99876543210

Permutation table p

Each digit is first permuted according to its position (row = position mod 8). This makes the same digit contribute differently depending on where it appears.

p0123456789
pos 00123456789
pos 11576283094
pos 25803796142
pos 38916043527
pos 49453126870
pos 54286573901
pos 62793806415
pos 77046913258

Inverse table inv

Only needed when generating a check digit, to find the digit that brings the running value back to 0.

c0123456789
inv[c]0432156789

The algorithm in pseudocode

Pseudocode
function verhoeffValid(number):
    c = 0
    digits = reverse(number)            // process right to left
    for i from 0 to length(digits) - 1:
        c = d[c][ p[i mod 8][ digits[i] ] ]
    return c == 0

function verhoeffCheckDigit(numberWithoutCheckDigit):
    c = 0
    digits = reverse(numberWithoutCheckDigit)
    for i from 0 to length(digits) - 1:
        c = d[c][ p[(i + 1) mod 8][ digits[i] ] ]
    return inv[c]

Validation processes the digits from right to left, starting with the check digit at position 0. Generation is identical except the positions are shifted by one (because the check digit does not exist yet) and the final value is looked up in inv.

Worked example: 9999 4105 7058

This is one of the test Aadhaar numbers UIDAI publishes for its developer sandbox, so it is safe to use as an example. Reverse the digits and walk through them:

iDigiti mod 8PermuteMultiply
080p[0][8] = 8d[0][8] = 8
151p[1][5] = 8d[8][8] = 0
202p[2][0] = 5d[0][5] = 5
373p[3][7] = 5d[5][5] = 0
454p[4][5] = 2d[0][2] = 2
505p[5][0] = 4d[2][4] = 1
616p[6][1] = 7d[1][7] = 8
747p[7][4] = 9d[8][9] = 4
890p[0][9] = 9d[4][9] = 8
991p[1][9] = 4d[8][4] = 9
1092p[2][9] = 2d[9][2] = 7
1193p[3][9] = 7d[7][7] = 0

The final value is 0, so the number is valid. Change any one digit and the final value will no longer be 0 — try it in the calculator above.

Common implementation mistakes

  • Processing left to right. The position index must count from the rightmost digit.
  • Using p[i mod 8] for generation. When computing a check digit, use p[(i + 1) mod 8] because the digits are shifted by the missing check digit.
  • Forgetting the first-digit rule. Verhoeff is only one of the Aadhaar rules; numbers starting with 0 or 1 are invalid regardless of checksum.
  • Validating with spaces in the string. Strip everything that is not a digit first.

Ready-to-use implementations are on the developer page.

Frequently asked questions

What is the Verhoeff algorithm?

The Verhoeff algorithm is a checksum formula published by Jacobus Verhoeff in 1969. It appends one check digit to a decimal number so that any single wrong digit and any swap of two adjacent digits can be detected. It is the check digit used in every Aadhaar number.

Why does Aadhaar use Verhoeff instead of Luhn?

The Luhn algorithm (credit cards) misses one adjacent transposition (09 and 90) and several twin errors. Verhoeff, built on the non-commutative dihedral group D5, detects all single-digit errors and all adjacent transpositions, which matters when 12-digit numbers are typed by hand across thousands of systems.

Which digit of an Aadhaar number is the check digit?

The last (12th) digit. The first 11 digits are random and the 12th is computed from them with the Verhoeff algorithm.

Does the Verhoeff algorithm prove an Aadhaar number is real?

No. It only proves the number is internally consistent. Roughly one in ten random 12-digit strings passes the checksum, so a valid checksum is necessary but not sufficient. Only UIDAI can confirm a number is issued.