Алгоритм Луна: как проверить номер карты по модулю 10

Алгоритм Луна (Luhn algorithm) - это простейшая контрольная сумма по модулю 10, которой проверяют, не ошибся ли оператор при вводе длинного номера. Его придумал Ганс Питер Лун, инженер IBM, в 1954 году и запатентовал в 1960-м (US Patent 2 950 048). Не путать с похоже звучащим алгоритмом Куна - тот решает задачу о максимальном паросочетании в двудольном графе и к контрольным суммам отношения не имеет. Сегодня по Луну валидируют номера банковских карт (PAN по стандарту ISO/IEC 7812), IMEI мобильных устройств, канадский Social Insurance Number, израильский Teudat Zehut, греческий идентификатор Φ.Α.Δ.Ν. и десятки других серий. Никакой криптографии в нём нет - задача только одна: поймать случайную опечатку до того, как номер уйдёт в систему.
Алгоритм пошагово
Алгоритм работает с любой последовательностью цифр. Шаги:
- Начиная с правой цифры, идти влево.
- Каждую вторую цифру (то есть стоящую на чётной позиции, если считать справа и нумеровать с единицы) - удвоить.
- Если результат удвоения больше 9 - вычесть 9 (что эквивалентно сложению цифр: ).
- Сложить все полученные числа (как удвоенные с поправкой, так и нетронутые).
- Если сумма удовлетворяет - номер валиден.
Формально для номера (где - крайняя правая цифра):
Условие - критерий валидности. Псевдокод в десять строк:
function luhn(digits):
sum = 0
parity = length(digits) mod 2
for i from 0 to length(digits) - 1:
d = digits[i]
if i mod 2 == parity:
d = d * 2
if d > 9: d = d - 9
sum = sum + d
return sum mod 10 == 0
Хочется не считать руками? Введите номер в поле ниже и выберите режим - проверка, расчёт контрольной цифры, пошаговая трассировка или сравнение с Verhoeff и Damm.
Подробный пример
Возьмём тестовый номер Visa и проверим его. Шестнадцать цифр, нумеруем справа налево.
| Позиция (справа) | Цифра | Удваивать? | Результат |
|---|---|---|---|
| 1 | 6 | нет | 6 |
| 2 | 6 | да | 12 → 3 |
| 3 | 3 | нет | 3 |
| 4 | 0 | да | 0 |
| 5 | 3 | нет | 3 |
| 6 | 8 | да | 16 → 7 |
| 7 | 2 | нет | 2 |
| 8 | 1 | да | 2 |
| 9 | 1 | нет | 1 |
| 10 | 5 | да | 10 → 1 |
| 11 | 1 | нет | 1 |
| 12 | 0 | да | 0 |
| 13 | 2 | нет | 2 |
| 14 | 3 | да | 6 |
| 15 | 5 | нет | 5 |
| 16 | 4 | да | 8 |
Сумма столбца «Результат»: . Деление на 10: . Номер валидный.
Если бы где-то проскочила одна ошибка - например, кассир ввёл вместо (изменили одну тройку) - сумма сдвинется ровно на ту разницу, которую алгоритм по построению не пропускает.
Что ловит, а что нет
Луна устроен так, чтобы дёшево поймать самые частые опечатки оператора. Реально он гарантирует:
- 100% обнаружение одиночной изменённой цифры. Любая замена одного меняет вклад в сумму на величину, не кратную 10 - кроме одного хитрого случая, описанного ниже.
- Около 90% обнаружения перестановок соседних цифр. Из десяти возможных пар-перестановок алгоритм пропускает только одну.
Что Луна не ловит:
- Перестановка . На паре соседних позиций одна из цифр обязательно удваивается. , . Сумма пары до перестановки: . После перестановки: . Одно и то же - обмен остался незамеченным.
- Подмена двух цифр, сохраняющая сумму. Если оператор ошибся сразу в двух разрядах так, что одна разница компенсировала другую (например, в одном и в другом с учётом удвоения) - Луна молчит.
- Любые умышленные подделки. Алгоритм публичный и тривиальный, любой школьник за минуту сгенерирует «правильный по Луну» номер, не соответствующий ни одному счёту.
Главное: Луна - это «детектор опечаток», а не защита от мошенничества. Реальная проверка карты делается на стороне эмитента через сеть Visa/Mastercard/Мир - там номер сверяется с базой выпущенных PAN, проверяется срок, CVV и 3-D Secure.
Зачем нужен - где применяется
Алгоритм Луна - почти универсальный стандарт там, где длинный номер вводят руками:
- PAN (Primary Account Number) банковских карт - основной потребитель. Стандарт ISO/IEC 7812 прямо предписывает Луна как контрольную цифру в 16-значном номере. Платёжные шлюзы (Stripe, PayPal, Adyen, ЮKassa) запускают Луна на стороне клиента ещё до отправки формы - это экономит сетевой round-trip на очевидные опечатки.
- IMEI мобильных устройств - 15-значный идентификатор, последняя цифра - контрольная по Луну. Когда вы набираете
*#06#и вводите IMEI в чёрный список оператора, Луна отсеивает заведомо неправильные. - Канадский SIN (Social Insurance Number) - 9 цифр, последняя по Луну.
- Израильский Teudat Zehut - 9-значный идентификатор личности.
- Греческий Φ.Α.Δ.Ν. - налоговый номер юридических лиц.
- NPI - National Provider Identifier, идентификатор медицинских работников в США.
Везде Луна выполняет одну и ту же роль: на стороне формы - поймать опечатку, на стороне бэкенда - отсечь явно битый ввод до тяжёлой проверки по базе.
Generation, не только validation
Зеркальная задача - сгенерировать контрольную цифру для нового номера. Алгоритм тот же, но запускается на известной цифре с подстановкой нуля на место контрольной, а потом ответ корректируется.
Пусть мы хотим выпустить карту с первыми 15 цифрами . Считаем сумму как обычно, но позиции теперь сдвинулись (контрольная цифра встанет на позицию 1 - нечётную, не удваивается):
где - сумма Луна по 15 «известным» цифрам с уже сдвинутой нумерацией. Для нашего примера , тогда . Контрольная цифра 6 - и полный номер совпал с тем, что мы проверяли выше.
Сравнение с другими checksum
Алгоритмов «контрольной суммы для коротких номеров» больше одного. Соседи Луна по нише:
- Verhoeff (1969). Голландский математик Якобус Верхуф построил схему на группе диэдра порядка 10. Это первая контрольная сумма, которая ловит все одиночные ошибки и все перестановки соседних цифр (включая злополучные ). Цена - табличное умножение и перестановка вместо простого удвоения.
- Damm (2004). Хайнрих Дамм нашёл квазигруппу порядка 10 без неподвижных точек, которая даёт те же гарантии, что Verhoeff, но проще описывается и реализуется одной таблицей .
- CRC (Cyclic Redundancy Check). Совсем из другой ниши: CRC проверяет блоки данных в десятки-сотни байт (Ethernet-кадры, ZIP-архивы), а не короткие номера. Стоимость выше, но и ошибки ловит куда более тонкие.
- MD5, SHA-1, SHA-256. Криптографические хеши - для проверки целостности файлов и подписей, а не для опечаток. На 16-значном номере применять SHA - стрелять из пушки по воробью и получить хеш длиннее самого номера.
Verhoeff и Damm строго лучше Луна по математике, но проигрывают в трёх вещах: их нельзя посчитать в уме, их таблицы надо хранить, и они появились на 15-50 лет позже - ниша банковских номеров была уже занята. Поэтому Луна жив и хорошо себя чувствует.
Реализации
Алгоритм укладывается в десяток строк на любом языке. Канонические шаблоны:
JavaScript (паттерн, который используют Stripe, ЮKassa и большинство фронтенд-валидаторов карт):
function luhn(num) {
const digits = String(num).replace(/\D/g, '').split('').map(Number);
const parity = digits.length % 2;
const sum = digits.reduce((acc, d, i) => {
if (i % 2 === parity) {
d *= 2;
if (d > 9) d -= 9;
}
return acc + d;
}, 0);
return sum % 10 === 0;
}
// Stripe test cards - все проходят Luhn, ни одной реальной транзакции
luhn('4242424242424242'); // true (Visa)
luhn('5555555555554444'); // true (Mastercard)
luhn('378282246310005'); // true (American Express)
Python (PyPI-пакет luhn ровно про это, но однострочник пишется без библиотек):
def luhn(num: str) -> bool:
digits = [int(c) for c in num if c.isdigit()]
s = sum(d if i % 2 == len(digits) % 2 else (d * 2 - 9 if d > 4 else d * 2)
for i, d in enumerate(digits))
return s % 10 == 0
Hardware. Чипы Visa/Mastercard на EMV-картах содержат микроконтроллер, который умеет сам считать Луна при выдаче ATC (Application Transaction Counter). На стороне POS-терминалов проверка часто хардварная - в FPGA уличных терминалов даже не используется CPU.
Тестовые карты для разработчиков
Платёжные провайдеры публикуют официальные тестовые номера, чтобы можно было прогонять Sandbox-транзакции и проверять интеграцию. Все они построены так, чтобы пройти Луна, но ни один не привязан к реальному счёту. Самые известные:
- Stripe -
4242 4242 4242 4242(Visa, успешная),4000 0000 0000 0002(отклонённая),5555 5555 5555 4444(Mastercard). - PayPal -
4032 0388 5605 2515и серия4111 1111 1111 1111. - Adyen -
5555 4444 3333 1111(Mastercard),4111 1111 4555 1142(Visa с 3-D Secure). - ЮKassa -
5555 5555 5555 4444для успеха,5555 5555 5555 4477для отказа.
Если в логах продакшена увидели один из этих номеров - это либо разработчик с боевой формы, либо бот, который не читал документацию. Реальной картой это быть не может.
Частые ошибки
- Путают чётность. На номерах с разной длиной (15 цифр у IMEI и AmEx, 16 у Visa, 19 у новых карт UnionPay) меняется, какая позиция удваивается. Правильный признак - «считать справа», а не «индекс в массиве».
- Делают
d * 2 - 10вместо- 9. Удвоение 5 → 10, и - но правильный ответ . Вычитать надо именно 9. - Запускают Луна и считают, что проверили карту. Луна - детектор опечаток, не подтверждение существования счёта. Авторизация делается через эмитента.
- Хранят PAN после проверки. PCI DSS требует никогда не сохранять полный номер карты в логах/БД на стороне мерчанта. Луна проверили - отдали в шлюз - забыли.
FAQ
Можно ли по алгоритму Луна определить тип карты (Visa, Mastercard)? Нет, Луна - только контрольная сумма. Тип определяется по первой цифре или нескольким первым (IIN/BIN-диапазон по ISO/IEC 7812): 4 - Visa, 51-55 и 2221-2720 - Mastercard, 34 и 37 - American Express, 2200-2204 - Мир.
Почему именно модуль 10, а не 11 или 7? Луна работал в эпоху механических калькуляторов IBM, и модуль 10 удобен ровно потому, что цифр в десятичной системе тоже 10 - никакой остаток нельзя выразить «лишней цифрой». Альтернатива - ISBN-10 с модулем 11 и символом X для остатка 10 - Луна явно избегал.
Чем отличается алгоритм Луна от алгоритма Verhoeff? Verhoeff (1969) гарантирует обнаружение всех одиночных ошибок и всех перестановок соседних цифр, тогда как Луна пропускает и ещё около 10% перестановок. Цена - табличное умножение в группе диэдра вместо устного удвоения.
Коротко
Алгоритм Луна - контрольная сумма по модулю 10 для длинных номеров: идём справа налево, удваиваем каждую вторую цифру (если результат больше 9 - вычитаем 9), складываем всё, делим на 10. Остаток ноль - номер прошёл. Применяется в банковских картах, IMEI, SIN и десятке других идентификаторов; ловит 100% одиночных ошибок и 90% перестановок соседних цифр, не ловит подмену и не защищает от подделки. Для математически строгих задач есть Verhoeff и Damm, но Луна остаётся стандартом де-факто из-за простоты и инерции 70 лет совместимости.
Читайте также

Алгоритм Прима - как построить остовное дерево по шагам
Разбираем, как алгоритм Прима шаг за шагом строит минимальное остовное дерево графа: идея жадного выбора, лемма о разрезе и трассировка на конкретном примере.

Алгоритм Эдмондса-Карпа: поиск максимального потока
Алгоритм Эдмондса-Карпа находит максимальный поток в сети: BFS ищет дополняющий путь, что даёт полиномиальную сложность. Разбираем идею, реализацию и оценку.

Алгоритм Куна: как найти максимальное паросочетание
Алгоритм Куна шаг за шагом: ищем увеличивающие цепи обычным DFS и находим максимальное паросочетание в двудольном графе за O(V·E), с разбором идеи и сложности.