Skip to content

Understanding the Luhn Algorithm

Published: at 12:21 AM

The Luhn Algorithm (also known as the Modulus 10 algorithm) is a simple checksum formula used to validate a variety of identification numbers, primarily credit card numbers. Here’s a step-by-step explanation of how it works:

Side-note: Before we proceed, not all credit or debit cards are based on the Luhn Algorithm. For more details, you can refer to this Stack Overflow post.

How the Luhn Algorithm Works

We’ll use this fake credit card number: 4539455591293228

var card_number = "4539455591293228";
  1. Reverse the Number: Start from the end and reverse the digits of the number.
// Luhn Algorithm
let is_valid_luhn = number =>
  !isNaN(number) &&
  number
    .split("")
    .reverse()
    .reduce((acc, c, i) => {
      if ((i + 1) % 2 == 0) {
        c *= 2;
        if (c > 9) c -= 9;
      }
      return acc + Number(c);
    }, 0) %
    10 ==
    0;
  1. Double Every Other Digit: Beginning with the second digit from the right, double every second digit.
bool alternate = false;
for (let i = card_number.length - 1; i >= 0; i--) {
  if (alternate) {
    // double the digit
  }
}
  1. Sum the Digits: If any results from the doubling step are greater than 9, subtract 9 from them or sum the individual digits of those products. Then, sum all the digits together.

  2. Check If Divisible by 10: If the total sum is divisible by 10, the number is valid according to the Luhn Algorithm.

Here’s a simple code example in C# for better understanding:

public static bool IsValidLuhn(string number) {
  int sum = 0;
  bool alternate = false;
  for (int i = number.Length - 1; i >= 0; i--) {
    int n = int.Parse(number[i].ToString());
    if (alternate) {
      n *= 2;
      if (n > 9) {
        n -= 9;
      }
    }
    sum += n;
    alternate = !alternate;
  }
  return (sum % 10 == 0);
}

This function returns true if the number is valid according to the Luhn Algorithm, and false otherwise.

We can also use the Luhn Algorithm to generate fake credit card numbers:

function generateCreditCardNumber(prefix, maxLength) {
  let number = prefix;
  // this is string concatenation
  while (number.length < maxLength) number += Math.floor(Math.random() * 10);
  // We want the sum of generated digits and the check digit, to be divisible by 10
  // For the check digit, we'll subtract the sum of generated digits from 10 and mod it by 10
  var checkDigit =
    (10 -
      number
        .split("")
        .reverse()
        .reduce((acc, c, i) => {
          if ((i + 1) % 2 > 0) {
            c *= 2;
            if (c > 9) c -= 9;
          }
          return acc + Number(c);
        }, 0)) %
    10;
  return number + checkDigit;
}

var visaPrefix = "4539"; // Visa prefix
var maxLength = 16;
console.log(generateCreditCardNumber(visaPrefix, maxLength));

Notes

  1. Validation vs Verification - Passing the Luhn check doesn’t guarantee a valid credit card
  1. Implementation Tips - Always validate input format before applying the algorithm

Previous Post
Generating a Valid Credit Card Number Using Luhn's Algorithm
Next Post
Implementing 3DS for Enhanced Payment Security