The Luhn Algorithm Explained: How Credit Card Validation Works
A step-by-step guide to the Luhn (mod-10) algorithm with a worked example for 4242 4242 4242 4242, why every card uses it, and how to implement it in code.
By FakeName Editorial TeamPublished June 25, 2026Last updated June 25, 20269 min read
The Luhn algorithm is a mod-10 checksum that detects accidental typos in number sequences like credit card numbers, and it is why a checkout form can flag a mistyped digit before any network request fires. IBM engineer Hans Peter Luhn designed it in 1954 and received US Patent 2,950,048 for it in 1960; today it sits behind nearly every payment card on earth [luhn-wiki]. This guide explains how it works, walks the math on a real test number, and gives a correct implementation.
To check a number right now, the credit card validator at /tools/credit-card-validator runs the full Luhn check in your browser and never transmits the digits anywhere. For Luhn-valid sandbox test cards, the credit card generator produces them on demand, and the full identity generator at / scopes a card to a complete fictional profile. Everything those tools emit is fictional and exists for testing, QA, and privacy work only, never for fraud or impersonation.
What does the Luhn algorithm actually do?
The Luhn algorithm computes a single check digit that makes an entire number satisfy a mod-10 arithmetic property, so any single-digit transcription error breaks the property and fails validation instantly. It is a checksum, not encryption: it carries no secret, anyone can compute it, and that is exactly the design goal. Its only job is catching the typos a human makes when copying digits.
The formula is published in Annex B of ISO/IEC 7812-1, the standard for identification card numbering, which is why it appears far beyond credit cards: in IMEI device identifiers (the 15th digit, per 3GPP TS 23.003), some social insurance numbers, and survey response IDs [iso7812]. That same standard defines the structure of a card number. Here is the anatomy of a typical 16-digit Visa or Mastercard number.
| Segment | Digit positions (from left) | Name | Purpose |
|---|---|---|---|
| MII | 1 | Major Industry Identifier | Broad issuer category (4 = banking/finance, used by Visa) |
| IIN / BIN | 1–6 (now extended to 8) | Issuer Identification Number | Identifies the issuing institution and card network |
| Account | 7–15 | Individual Account Identifier | Up to 12 digits identifying the specific account |
| Check | 16 | Luhn check digit | Single digit that makes the whole number mod-10 valid |
How does the Luhn algorithm work step by step?
To validate a number with Luhn, start at the rightmost digit, double every second digit moving left, subtract 9 from any doubled result above 9, sum all the digits, and confirm the total is divisible by 10. Those four steps run in linear time with no lookup beyond single-digit arithmetic. The list below states them precisely.
- Starting from the rightmost digit (the check digit), leave it as is and double every second digit moving left.
- If doubling a digit produces a number greater than 9, subtract 9 from it (equivalently, add the two digits of the result, which always lands in the range 1 to 9).
- Sum every digit: the untouched digits plus the transformed (doubled) digits.
- If the total is divisible by 10, the number passes the Luhn check. Otherwise it fails.
The subtract-9 step is where most hand calculations go wrong. Doubling 8 gives 16, and 16 minus 9 is 7, which equals 1 + 6, the sum of its digits. That shortcut keeps every contribution to a single digit. Memorize the full mapping from input digit to doubled contribution and you can run Luhn on paper in seconds.
| Input digit | Doubled value | After subtract-9 rule | Net contribution |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 1 | 2 | 2 | 2 |
| 2 | 4 | 4 | 4 |
| 3 | 6 | 6 | 6 |
| 4 | 8 | 8 | 8 |
| 5 | 10 | 10 − 9 = 1 | 1 |
| 6 | 12 | 12 − 9 = 3 | 3 |
| 7 | 14 | 14 − 9 = 5 | 5 |
| 8 | 16 | 16 − 9 = 7 | 7 |
| 9 | 18 | 18 − 9 = 9 | 9 |
Worked example: why 4242 4242 4242 4242 passes
4242 4242 4242 4242 is Stripe's canonical Visa test number, used in sandbox environments worldwide [stripe-test]. It is built to pass Luhn while never mapping to a real account. The table below shows every position. Position 1 is the rightmost digit, and we double the even-numbered positions counting from the right.
| Position (from right) | Digit | Doubled? | Value after rule | Notes |
|---|---|---|---|---|
| 1 | 2 | No | 2 | Check digit, untouched |
| 2 | 4 | Yes | 8 | 4 x 2 = 8 |
| 3 | 2 | No | 2 | Untouched |
| 4 | 4 | Yes | 8 | 4 x 2 = 8 |
| 5 | 2 | No | 2 | Untouched |
| 6 | 4 | Yes | 8 | 4 x 2 = 8 |
| 7 | 2 | No | 2 | Untouched |
| 8 | 4 | Yes | 8 | 4 x 2 = 8 |
| 9 | 2 | No | 2 | Untouched |
| 10 | 4 | Yes | 8 | 4 x 2 = 8 |
| 11 | 2 | No | 2 | Untouched |
| 12 | 4 | Yes | 8 | 4 x 2 = 8 |
| 13 | 2 | No | 2 | Untouched |
| 14 | 4 | Yes | 8 | 4 x 2 = 8 |
| 15 | 2 | No | 2 | Untouched |
| 16 | 4 | Yes | 8 | 4 x 2 = 8 |
Add the values: eight untouched 2s sum to 16, and eight doubled 8s sum to 64. The total is 16 + 64 = 80, and since 80 is divisible by 10, the number is Luhn-valid. None of the doubled values exceeded 9 here, so the subtract-9 step never fired. A number like 49927398716 does trigger it, which is why you should test implementations against varied inputs.
A check digit is a form of redundancy check used for error detection, the decimal equivalent of a binary check bit. It consists of a single digit computed from the other digits in the number.
How do you compute the check digit when generating a number?
To generate a valid number, set the check digit to 0, run the same doubling-and-summing pass over the body, then pick the check digit using check digit = (10 − (sum mod 10)) mod 10. If the partial sum ends in 7, the check digit is 3; if it ends in 0, the check digit is 0. Test-data generators, including the one at /, use exactly this construction to produce numbers that survive front-end validation while staying in non-issued ranges. The faker ecosystem applies the same approach in its finance module [faker].
What does Luhn catch and what does it miss?
Luhn catches 100% of single-digit errors and most adjacent transpositions, but it misses the swap of 09 and 90, certain twin-digit substitutions like 22 to 55, and it says nothing about whether a card exists or is funded. Knowing these gaps keeps you from over-trusting a pass. The table below maps each error class to whether Luhn detects it.
| Error type | Example | Caught by Luhn? |
|---|---|---|
| Single mistyped digit | 4242...4242 becomes 4252...4242 | Yes, always (100%) |
| Most adjacent transpositions | Swapping 45 to 54 | Yes |
| Transposition of 09 and 90 | Swapping 09 to 90 | No (blind spot) |
| Twin-digit error 22 to 55 | 22 becomes 55 | No |
| Twin-digit error 33 to 66 | 33 becomes 66 | No |
| Whether the card exists | Any valid-format number | No, out of scope |
| Whether funds are available | Any valid number | No, out of scope |
The 09-to-90 swap is the most cited weakness: doubling 0 gives 0 and doubling 9 gives 9 (after subtracting 9), so swapping those two digits leaves the checksum unchanged [luhn-wiki]. The twin-digit substitutions fail for the same parity reason. Higher-assurance identifiers use the Verhoeff or Damm algorithms, which catch all single-digit and all adjacent-transposition errors. Bank accounts go further: an IBAN carries a two-digit checksum computed with ISO/IEC 7064 MOD 97-10, far stronger than Luhn but more expensive to run. Here is where Luhn sits among common schemes.
| Algorithm | Base / radix | All single-digit errors | All adjacent transpositions | Typical use |
|---|---|---|---|---|
| Luhn (mod 10) | Decimal | Yes | No (misses 09→90) | Credit cards, IMEI, IINs |
| Verhoeff | Decimal | Yes | Yes | India's Aadhaar number, high-assurance IDs |
| Damm | Decimal | Yes | Yes | Modern ID schemes |
| ISO/IEC 7064 (MOD 97-10) | Decimal | Yes | Yes | IBAN bank account numbers |
| UPC / EAN (mod 10) | Decimal | Yes | No | Retail barcodes |
How do you implement a Luhn validator correctly?
A correct Luhn validator normalizes input first (strip spaces and dashes, reject non-numeric or empty strings), then reads the digits right to left, doubles alternate digits, applies the subtract-9 rule, and returns whether the sum is divisible by 10. Keep the function pure: string in, boolean out, no shared mutable state. The decision table below lists the boundary cases your tests must cover.
| Input | After normalization | Expected result | Reason |
|---|---|---|---|
| 4242 4242 4242 4242 | 4242424242424242 | Valid | Sum 80, divisible by 10 |
| 4242-4242-4242-4242 | 4242424242424242 | Valid | Dashes stripped, same digits |
| 4242 4242 4242 4241 | 4242424242424241 | Invalid | Sum 79, fails mod-10 |
| 49927398716 | 49927398716 | Valid | Exercises the subtract-9 branch |
| 4242abc4242 | rejected | Invalid (error) | Non-numeric characters present |
| (empty string) | rejected | Invalid (error) | No digits to validate |
Most libraries follow this shape; the faker ecosystem, for instance, generates card numbers that pass Luhn by construction [faker]. Test your version against known-valid numbers like 4242 4242 4242 4242 and 49927398716 (which forces the subtract-9 branch), plus known-invalid numbers made by changing one digit, so every code path actually runs.
Why use synthetic card numbers instead of real ones?
Synthetic card numbers are the only safe option for testing because real cardholder data falls under PCI DSS and, in the EU, under the GDPR definition of personal data in Article 4(1), which covers any information relating to an identified or identifiable person [gdpr-art4]. Using someone's real card for QA is a processing activity with no lawful basis under GDPR Article 6. Synthetic numbers look right to your validation layer but identify no one. The UK Information Commissioner's Office treats properly synthesized data as falling outside personal-data obligations precisely because no individual is identifiable from it [ico-anon].
To go further, pair the checksum with structural lookups. The BIN range and card brand live in the leading digits; the validator at /tools/credit-card-validator decodes those alongside the Luhn pass, the generator at / produces complete, internally consistent fictional records for end-to-end suites, and /countries aligns those records with regional formats. Use Luhn as your fast local first filter, and let the payment network be the source of truth for everything else.
References & sources
- Luhn algorithm — Wikipedia
- ISO/IEC 7812-1: Identification cards — Identification of issuers — Part 1: Numbering system — International Organization for Standardization
- Testing — Sample test cards — Stripe Documentation
- @faker-js/faker — Finance module (creditCardNumber) — faker-js
- NIST SP 800-122: Guide to Protecting the Confidentiality of Personally Identifiable Information (PII) — National Institute of Standards and Technology
- GDPR Article 4 — Definitions (personal data) — gdpr-info.eu
- Anonymisation, pseudonymisation and privacy enhancing technologies guidance — UK Information Commissioner's Office
Frequently asked questions
What is the Luhn algorithm used for?+
The Luhn algorithm is a checksum formula that validates identification numbers such as credit card numbers, IMEI device numbers, and some national IDs. It detects accidental data-entry errors like a single mistyped digit or a swapped pair of adjacent digits before a number is submitted to a backend system. It is standardized in Annex B of ISO/IEC 7812-1.
Does passing the Luhn check mean a credit card is valid?+
No. Passing Luhn only means the digits form a mathematically consistent number. It does not mean the card was issued, is active, has funds, or belongs to anyone. Real authorization requires the card network and issuing bank. Luhn is purely a front-end typo filter.
Why is 4242 4242 4242 4242 a valid card number?+
It is Stripe's well-known sandbox test number, deliberately constructed to pass the Luhn check (its digit sum is 80, which is divisible by 10) while never being issued to a real account. It lets developers test payment flows without using real card data.
Which digit does the Luhn algorithm not double?+
Working from the rightmost digit, the last digit (the check digit) is never doubled. You double every second digit moving left, so the doubling applies to positions 2, 4, 6 and so on counting from the right.
Can the Luhn algorithm catch every typo?+
No. It reliably catches every single-digit error and most adjacent transpositions, but it misses the specific transposition of 09 to 90 (and vice versa) and certain twin-digit errors like 22 to 55. It is a lightweight first line of defense, not a guarantee.