ISIN Check Digit Validation: How the Luhn Algorithm Works

Last updated: February 2026 · 9 min read

Every ISIN ends with a single check digit calculated using the Luhn algorithm. This digit catches transcription errors—swapped digits, single-character typos—with over 90% accuracy. This guide walks through the exact calculation with real ISINs, covers common implementation pitfalls, and provides working pseudocode.

What the Check Digit Catches

The Luhn algorithm detects:

  • Any single-digit error (replacing one digit with another)
  • Most adjacent transposition errors (swapping two consecutive digits)
  • Most twin errors (e.g., 11 → 22)

It does not catch all transposition errors (e.g., swapping 0↔9) or more complex multi-digit errors. It's a quick sanity check, not a cryptographic guarantee.

Step-by-Step Calculation

Let's validate the ISIN US0378331005 (Apple Inc.) step by step.

Step 1: Convert Letters to Numbers

Replace each letter with its numeric value: A=10, B=11, ..., Z=35. Digits remain unchanged.

ISIN:     U     S     0  3  7  8  3  3  1  0  0  5
Values:   30    28    0  3  7  8  3  3  1  0  0  5
Expanded: 3  0  2  8  0  3  7  8  3  3  1  0  0  5

Step 2: Apply Luhn from the Right

Starting from the rightmost digit, double every second digit. If the result is > 9, subtract 9:

Position (R→L):  14  13  12  11  10  9   8   7   6   5   4   3   2   1
Digits:           3   0   2   8   0   3   7   8   3   3   1   0   0   5
Double even pos:  6   0   4   8   0   3  14   8   6   3   2   0   0   5
Subtract 9 if>9:  6   0   4   8   0   3   5   8   6   3   2   0   0   5
                                        (14-9=5)

Step 3: Sum All Digits

Sum = 6+0+4+8+0+3+5+8+6+3+2+0+0+5 = 50
50 mod 10 = 0 ✓ (valid ISIN)

For validation: if the sum mod 10 equals 0, the ISIN is valid. For calculation: the check digit is (10 - (sum_without_check mod 10)) mod 10.

More Examples

ISINCompanyExpanded DigitsSumValid?
US0378331005Apple Inc.3 0 2 8 0 3 7 8 3 3 1 0 0 550
DE0007664039Volkswagen1 3 1 4 0 0 0 7 6 6 4 0 3 960
GB0005405286HSBC1 6 1 1 0 0 0 5 4 0 5 2 8 650
US0378331006(invalid)3 0 2 8 0 3 7 8 3 3 1 0 0 651

Implementation in Code

JavaScript

function validateISIN(isin) {
  if (!/^[A-Z]{2}[A-Z0-9]{9}[0-9]$/.test(isin)) return false;
  
  // Convert to digit string
  let digits = '';
  for (const ch of isin) {
    if (ch >= 'A' && ch <= 'Z') {
      digits += (ch.charCodeAt(0) - 55).toString(); // A=10, B=11...
    } else {
      digits += ch;
    }
  }
  
  // Luhn from right
  let sum = 0;
  let alt = false;
  for (let i = digits.length - 1; i >= 0; i--) {
    let n = parseInt(digits[i]);
    if (alt) {
      n *= 2;
      if (n > 9) n -= 9;
    }
    sum += n;
    alt = !alt;
  }
  
  return sum % 10 === 0;
}

// Test
console.log(validateISIN('US0378331005')); // true
console.log(validateISIN('US0378331006')); // false

Python

def validate_isin(isin: str) -> bool:
    if len(isin) != 12:
        return False
    
    # Convert letters to numbers
    digits = ''
    for ch in isin:
        if ch.isalpha():
            digits += str(ord(ch) - ord('A') + 10)
        else:
            digits += ch
    
    # Luhn algorithm
    total = 0
    for i, d in enumerate(reversed(digits)):
        n = int(d)
        if i % 2 == 1:  # double every second from right
            n *= 2
            if n > 9:
                n -= 9
        total += n
    
    return total % 10 == 0

# Test
assert validate_isin('US0378331005') == True
assert validate_isin('DE0007664039') == True
assert validate_isin('US0378331006') == False

Common Implementation Bugs

⚠️ Bug #1: Wrong doubling direction. The Luhn algorithm doubles from the right, not the left. Because letter-to-number conversion produces variable-length digit strings (A→10 is 2 digits, 5→5 is 1 digit), the total length varies. You must process from right to left.

⚠️ Bug #2: Forgetting letter conversion. ISINs contain letters (country code + possibly in the national ID). If you skip the letter→number conversion, the algorithm will produce wrong results.

⚠️ Bug #3: Off-by-one in calculation vs validation. For validation, include the check digit in the sum and verify sum % 10 == 0. For calculation, exclude the check digit, compute the sum, then check digit = (10 - sum % 10) % 10. Mixing these up is a common source of errors.

⚠️ Bug #4: Using the same code for CUSIP check digits. CUSIP uses a different variation of Luhn with different position weighting. Don't reuse ISIN validation for CUSIP or vice versa.

Check Digit Algorithms Compared

IdentifierAlgorithmLetter ConversionDirection
ISINLuhn (standard)A=10, B=11, ..., Z=35Right to left
CUSIPModified LuhnA=10, B=11, ..., Z=35, *=36, @=37, #=38Right to left, different weighting
SEDOLWeighted sum mod 10B=11, C=12, ..., Z=35 (no vowels)Left to right, weights: 1,3,1,7,3,9
WKNNoneN/AN/A
VALORNoneN/AN/A

Frequently Asked Questions

Can two different ISINs have the same check digit?

Yes, absolutely. The check digit is a single digit (0-9), so roughly 10% of all ISINs share any given check digit. The check digit only validates that specific ISIN—it's not a unique identifier on its own.

What happens if I compute the check digit and it doesn't match?

The ISIN is either mistyped or corrupted. Check for common errors: swapped digits, wrong character, extra/missing character. If the country code is wrong, the entire ISIN will be invalid.

Is there a standard library for ISIN validation?

Most languages have packages: Python has python-stdnum (stdnum.isin), JavaScript has isin-validator on npm, Java has Apache Commons Validator. For one-off checks, our converter tool validates ISINs automatically.

Validate & Convert ISINs

Our tool validates the check digit automatically and converts between ISIN, CUSIP, WKN, SEDOL, and more.

Open Converter →