모두의 계산기
← 블로그로 돌아가기

재미있는 숫자 상식

룬 알고리즘 계산법: 짝수 번째 숫자를 2배로 만들어 카드번호를 검증하는 원리

오른쪽에서 두 번째 숫자부터 한 자리씩 건너 2배하고 각 자릿수를 더해 합계가 10의 배수인지 확인하는 Luhn 알고리즘과 검증 숫자 생성법을 예제로 설명합니다.

온라인 결제창에 카드번호를 잘못 입력하면 서버가 결제를 요청하기도 전에 번호 형식이 올바르지 않다는 안내가 나타날 때가 있습니다. 숫자를 한 자리 빠뜨리거나 서로 붙어 있는 두 자리를 바꿔 쓴 실수를 빠르게 찾아내는 데 널리 쓰이는 계산법이 룬 알고리즘(Luhn algorithm)입니다. 모듈러스 10 또는 Mod 10 공식이라고도 부릅니다.

계산 방법은 간단합니다. 완성된 번호의 오른쪽 끝에는 검증 숫자 한 자리가 있다고 보고, 오른쪽에서 두 번째 숫자부터 한 자리씩 건너가며 2배합니다. 2배한 값이 두 자리가 되면 두 자릿값을 더하거나 9를 뺍니다. 바뀐 숫자와 그대로 둔 숫자를 모두 더해 합계가 10의 배수이면 룬 검사를 통과합니다. 다만 통과했다는 사실은 번호 구조의 체크섬이 맞는다는 뜻일 뿐, 실제로 발급된 카드인지 또는 현재 사용할 수 있는지는 알려 주지 않습니다.

룬 알고리즘이란 무엇인가

룬 알고리즘은 여러 자리 숫자의 마지막에 붙이는 검증 숫자, 즉 체크 디지트(check digit)를 계산하는 오류 검출 방식입니다. 원래 데이터로 체크 디지트를 만들고, 나중에 전체 번호를 같은 규칙으로 계산해 입력이나 전달 과정에서 숫자가 달라졌는지 확인합니다. 결과를 10으로 나눈 나머지를 이용하므로 Mod 10 알고리즘이라는 이름도 사용합니다.

이 방식은 IBM 연구자 한스 페터 룬(Hans Peter Luhn)이 고안했습니다. 미국 특허 US 2,950,048은 1954년 1월 6일 출원되어 1960년 8월 23일 등록됐습니다. 특허의 명칭은 ‘숫자를 검증하는 계산기’이며, 숫자 오른쪽에 체크 디지트를 붙여 전사 과정의 오류와 자릿수 교환을 확인하는 장치와 계산 원리를 설명합니다.

오른쪽에서 세어야 하는 이유

‘짝수 번째 숫자를 2배한다’는 설명은 기준 방향을 빠뜨리면 틀린 결과를 만들 수 있습니다. 완성된 번호를 검증할 때는 가장 오른쪽의 체크 디지트를 1번째로 세고, 그 왼쪽을 2번째로 셉니다. 오른쪽 기준 2·4·6·8번째처럼 짝수 위치의 숫자를 2배합니다. 체크 디지트 자체는 2배하지 않습니다.

검증할 때: 오른쪽 끝 체크 디지트는 그대로 두고, 오른쪽에서 두 번째 숫자부터 한 자리씩 건너 2배합니다.

아직 체크 디지트가 없는 본문 숫자에서 새 체크 디지트를 만들 때는 규칙이 한 칸 이동해 보입니다. 본문 오른쪽 끝 숫자가 나중에 체크 디지트의 왼쪽, 즉 완성된 번호의 오른쪽 두 번째 자리가 되기 때문입니다. 따라서 본문만 놓고 계산할 때는 가장 오른쪽 숫자부터 2배합니다. 왼쪽에서 홀수 번째나 짝수 번째라는 표현은 번호 길이가 달라지면 바뀔 수 있으므로 오른쪽 끝을 기준으로 구현하는 편이 안전합니다.

작업오른쪽 끝 숫자 처리그다음 처리
완성된 번호 검증체크 디지트이므로 그대로왼쪽 숫자를 2배
체크 디지트 생성본문의 마지막 숫자를 2배그 왼쪽 숫자는 그대로

룬 알고리즘 검증 순서

  1. 공백과 구분 기호를 제거하고 0부터 9까지의 숫자열을 준비합니다.
  2. 가장 오른쪽 체크 디지트는 그대로 둡니다.
  3. 오른쪽에서 두 번째 숫자부터 한 자리씩 건너가며 2배합니다.
  4. 2배한 결과가 10 이상이면 두 자릿수를 더하거나 결과에서 9를 뺍니다.
  5. 변환한 숫자와 그대로 둔 숫자를 모두 더합니다.
  6. 합계를 10으로 나눈 나머지가 0인지 확인합니다.
유효 조건: 전체 변환 합계 mod 10 = 0

PCI 보안 표준 협의회도 결제카드의 주 계정번호(PAN)를 확인할 때 오른쪽에서 두 번째 자리부터 교대로 2배하고, 변환값과 나머지 숫자를 더한 합계가 10으로 나누어떨어지는지 검사하는 절차를 안내합니다. ISO/IEC 7812-1은 카드 발급자 식별번호와 PAN의 번호 체계를 규정하는 국제표준입니다.

2배한 값에서 왜 9를 빼는가

2배할 숫자가 0부터 4까지라면 결과는 0, 2, 4, 6, 8로 한 자리입니다. 5부터 9까지를 2배하면 10, 12, 14, 16, 18이 됩니다. 이때 각 자릿수를 더하면 1, 3, 5, 7, 9입니다. 10부터 18 사이의 두 자리 수에서 십의 자리 1과 일의 자리를 더한 결과는 원래 값에서 9를 뺀 것과 같습니다.

원래 숫자2배자릿수 합빠른 계산
0000
1222
2444
3666
4888
5101+0=110-9=1
6121+2=312-9=3
7141+4=514-9=5
8161+6=716-9=7
9181+8=918-9=9

따라서 변환 함수 f(d)는 d가 0~4이면 2d, 5~9이면 2d-9라고 쓸 수 있습니다. ‘2배한 뒤 각 자릿수를 더한다’와 ‘2배한 값이 9보다 크면 9를 뺀다’는 완전히 같은 계산입니다. 프로그램에서는 후자가 더 간단한 경우가 많습니다.

79927398713을 단계별로 검증하기

대표적인 예제 번호 79927398713을 검증해 보겠습니다. 가장 오른쪽의 3은 체크 디지트이므로 그대로 둡니다. 오른쪽에서 두 번째인 1부터 왼쪽으로 한 자리씩 건너 1, 8, 3, 2, 9를 2배합니다. 왼쪽부터 표로 정리하면 다음과 같습니다.

원래 숫자오른쪽 기준 위치처리합계에 넣을 값
711번째그대로7
910번째2배: 18→1+89
99번째그대로9
28번째2배4
77번째그대로7
36번째2배6
95번째그대로9
84번째2배: 16→1+67
73번째그대로7
12번째2배2
31번째체크 디지트 그대로3
7+9+9+4+7+6+9+7+7+2+3 = 70

합계 70은 10으로 나누어떨어지므로 79927398713은 룬 검사를 통과합니다. 마지막 숫자를 4로 잘못 입력해 79927398714가 되면 합계는 71이고 나머지가 1이므로 검사를 통과하지 못합니다. 이 검사는 숫자열이 룬 규칙과 일치하는지만 확인합니다. 실제 카드번호로 발급되었다는 뜻은 아닙니다.

체크 디지트 3을 새로 만드는 계산

이번에는 본문 7992739871만 있고 마지막 체크 디지트를 만들어야 한다고 하겠습니다. 본문의 가장 오른쪽 숫자 1은 체크 디지트가 붙으면 오른쪽 두 번째가 되므로 1부터 2배합니다. 이어서 7은 그대로, 8은 2배하는 식으로 번갈아 계산합니다. 변환값의 합은 67입니다.

67에 한 자리 숫자 c를 더해 10의 배수가 되게 해야 합니다. 67 다음의 10의 배수는 70이므로 c=3입니다. 합계가 이미 10의 배수라면 체크 디지트는 0이어야 하므로, 모든 경우를 하나의 식으로 처리하려면 바깥쪽에 한 번 더 mod 10을 적용합니다.

체크 디지트 c = (10 - (본문 변환 합계 mod 10)) mod 10
c = (10 - (67 mod 10)) mod 10 = (10-7) mod 10 = 3

계산한 3을 본문 오른쪽에 붙이면 79927398713이 됩니다. 전체 번호를 다시 검증하면 합계가 70이 되어 나머지가 0입니다. 체크 디지트를 생성한 뒤 전체 번호를 한 번 더 검증하는 절차는 구현 과정의 방향이나 홀짝 기준 실수를 찾는 데 도움이 됩니다.

모듈러 연산으로 보는 룬 공식

어떤 정수를 10으로 나눈 나머지는 0부터 9 가운데 하나입니다. 룬 알고리즘은 각 위치의 숫자를 변환한 합 S가 S≡0 (mod 10)을 만족하도록 체크 디지트를 정합니다. 합계의 일의 자리가 0인지 본다는 말과 같습니다. 70, 120, 190은 모두 10으로 나눈 나머지가 0이므로 유효한 합계입니다.

교대로 다른 변환을 적용하는 이유는 단순히 모든 숫자를 더하는 방식의 약점을 보완하기 위해서입니다. 숫자를 그대로 더하기만 하면 27과 72의 합이 모두 9여서 자리 교환을 알아낼 수 없습니다. 룬 방식에서는 한 위치에 2배 변환을 적용하고 이웃 위치는 그대로 두므로 대부분의 인접 자리 교환이 합계를 바꿉니다.

룬 알고리즘이 찾아낼 수 있는 오류

한 자리 숫자를 다른 숫자로 잘못 입력한 경우

룬 알고리즘은 한 자리 대체 오류를 모두 검출합니다. 그대로 더하는 위치에서는 0~9가 서로 다른 값을 냅니다. 2배하는 위치에서도 변환 결과가 0, 2, 4, 6, 8, 1, 3, 5, 7, 9로 모두 다릅니다. 따라서 한 자리만 다른 숫자로 바뀌면 합계의 나머지가 달라져 검증에 실패합니다.

서로 붙어 있는 두 숫자의 순서를 바꾼 경우

대부분의 인접 자리 교환도 검출합니다. 예를 들어 한쪽 위치에는 2배 변환이, 다른 위치에는 그대로 더하는 규칙이 적용되므로 27을 72로 바꾸면 두 자리의 합계 기여가 달라집니다. 한스 페터 룬의 특허도 단순 합산으로는 순서 교환을 구별할 수 없어 교대 대체 숫자를 사용한다고 설명합니다.

검출하지 못하는 대표적인 오류

09와 90의 자리 교환

룬 알고리즘은 인접한 09가 90으로 바뀌거나 90이 09로 바뀌는 오류를 검출하지 못합니다. 한 자리에는 그대로 더하기, 다른 자리에는 2배 변환을 적용해도 두 경우의 합계 기여가 모두 9가 되기 때문입니다.

09: 0 + f(9) = 0+9 = 9, 90: 9 + f(0) = 9+0 = 9

같은 숫자끼리의 교환은 번호 자체가 달라지지 않으므로 오류로 관찰되지 않습니다. 서로 다른 인접 숫자의 실제 자리 교환 가운데 룬 공식이 놓치는 대표적인 경우가 09↔90입니다. 그 밖에도 둘 이상의 숫자가 동시에 바뀌어 합계 변화가 서로 상쇄되면 검사를 통과할 수 있습니다.

여러 자리 오류와 숫자 누락

체크 디지트는 오류를 모두 교정하는 코드가 아닙니다. 여러 자리가 함께 바뀌어 변환 합계가 다시 10의 배수가 되면 검출되지 않습니다. 숫자를 한 자리 빠뜨리거나 추가하면 그 뒤의 홀짝 위치가 전부 바뀌므로 많은 경우 실패하지만, 가능한 모든 삽입·삭제 오류를 검출한다고 보장할 수는 없습니다. 번호 체계에서 정한 길이 검사와 룬 검사를 함께 적용해야 합니다.

룬 검사는 보안 인증이나 암호화가 아니다

룬 체크 디지트는 앞자리만 알면 누구나 계산할 수 있습니다. 비밀키가 없고 역산을 막는 성질도 없으므로 암호학적 해시, 전자서명, 인증번호가 아닙니다. 의도적으로 룬 조건을 만족하는 숫자열을 만드는 것도 어렵지 않습니다. 목적은 악의적인 위조를 막는 것이 아니라 우연한 입력 오류를 빠르게 거르는 것입니다.

  • 룬 통과만으로 실제 발급된 카드번호인지 알 수 없습니다.
  • 카드가 활성 상태인지, 정지되었는지 또는 만료되었는지 알 수 없습니다.
  • 카드 소유자, 유효기간, 보안코드가 맞는지 확인하지 않습니다.
  • 계좌 잔액이나 결제 승인 가능 여부를 확인하지 않습니다.
  • 도난·복제 번호인지 판별하는 사기 탐지 기능이 아닙니다.

PCI 보안 표준 협의회도 룬 공식이 결제카드 번호로 가능한 형식을 확인할 뿐, 실제로 발급되어 활성화된 번호인지는 알려 주지 않는다고 명시합니다. 실제 결제 가능 여부는 카드사나 결제망의 승인 절차를 거쳐야 확인됩니다.

카드번호 이외에 사용되는 사례

룬 공식은 결제카드 PAN 외의 식별번호에도 사용됩니다. 3GPP TS 23.003은 휴대전화 단말기 식별번호인 IMEI의 14자리 본문에 룬 체크 디지트를 계산해 15번째 숫자로 붙이는 절차를 규정합니다. 이 체크 디지트의 목적은 도난 단말을 고객센터에 등록하는 상황 같은 수동 전달 오류를 줄이는 것입니다.

미국의 국가 의료제공자 식별번호(NPI)도 Luhn Mod 10 공식을 사용하지만, 계산할 때 의료용 카드 발급자 접두어 80840을 반영하는 별도 규칙이 있습니다. 따라서 어떤 번호가 룬 계열 공식을 쓴다는 사실만으로 일반 카드번호와 완전히 같은 전처리 규칙을 적용해서는 안 됩니다. 각 번호 체계의 공식 규격을 확인해야 합니다.

모든 체크 디지트가 룬 알고리즘을 사용하는 것도 아닙니다. 국제은행계좌번호 IBAN은 MOD 97-10을 사용하고, 상품 식별번호 GTIN 계열은 1과 3의 교대 가중치를 쓰는 Mod 10 계산을 사용합니다. 둘 다 나머지 연산을 이용하지만 룬의 2배 후 자릿수 합산 규칙과는 다른 알고리즘입니다.

프로그램으로 구현할 때 주의할 점

번호는 정수가 아니라 문자열로 처리한다

식별번호는 계산할 금액이 아니라 숫자로 이루어진 코드입니다. 정수형으로 바꾸면 맨 앞의 0이 사라질 수 있고, JavaScript에서는 Number가 정확하게 표현할 수 있는 정수 범위를 넘는 긴 번호가 반올림될 수 있습니다. 입력은 문자열로 유지한 채 문자 하나씩 0~9인지 확인하고 계산해야 합니다.

공백과 하이픈을 제거하되 다른 문자는 거부한다

사람이 읽기 쉽게 넣은 공백이나 허용된 하이픈은 검증 전에 제거할 수 있습니다. 그러나 모든 비숫자 문자를 무조건 삭제하면 잘못된 입력이 조용히 다른 번호로 바뀔 수 있습니다. 서비스가 허용하는 구분자만 명시적으로 정리하고, 그 밖의 문자가 있으면 오류로 처리하는 편이 데이터 검증에 적합합니다.

검증과 체크 디지트 생성을 분리한다

완성된 번호 검증은 체크 디지트를 그대로 두고 그 왼쪽부터 2배합니다. 생성은 본문의 오른쪽 끝부터 2배한 뒤 부족한 값을 계산합니다. 두 기능에서 시작 위치가 다르므로 하나의 반복문을 재사용한다면 체크 디지트 포함 여부를 분명히 전달해야 합니다. 길이만 보고 왼쪽 첫 숫자의 배수를 정하는 구현은 요구사항이 바뀔 때 오류가 생기기 쉽습니다.

검증 의사코드: 오른쪽부터 이동 → 첫 자리는 그대로 → 다음 자리는 2배·9 초과 시 9 빼기 → 교대 반복 → 합계 % 10 === 0
생성 의사코드: 본문 오른쪽부터 이동 → 첫 자리부터 2배 → 교대 반복 → check=(10-(합계%10))%10

룬 검증기에서 함께 확인해야 할 항목

  • 입력이 비어 있지 않은지 확인합니다.
  • 허용된 구분자를 정리한 뒤 숫자만 남았는지 확인합니다.
  • 대상 번호 체계가 요구하는 길이와 접두어 규칙을 확인합니다.
  • 체크 디지트가 포함된 번호인지 본문만 받은 것인지 구분합니다.
  • 오른쪽 기준 홀짝 위치를 사용했는지 확인합니다.
  • 룬 통과 결과를 발급·활성·소유권 확인 결과로 표시하지 않습니다.
  • 실제 민감한 카드번호를 로그나 분석 도구에 기록하지 않습니다.

결제 서비스에서 카드번호를 취급할 때는 체크섬 계산과 별도로 PCI DSS 등 관련 보안 요구사항을 따라야 합니다. 룬 알고리즘이 단순하다고 해서 실제 카드번호를 불필요하게 저장하거나 노출해도 되는 것은 아닙니다. 가능하면 결제대행사의 토큰화된 입력 방식과 공식 SDK를 사용하고 민감정보의 처리 범위를 줄여야 합니다.

룬 알고리즘에 관한 자주 묻는 질문

짝수 번째 숫자는 왼쪽에서 세나요?

완성된 번호를 검증할 때는 오른쪽 끝 체크 디지트를 1번째로 보고 오른쪽에서 짝수 번째인 숫자를 2배합니다. 번호 길이가 고정된 경우에는 왼쪽 기준 규칙으로 바꾸어 표현할 수 있지만, 길이가 달라지면 홀짝이 뒤집힙니다. 오른쪽 기준이 가장 일반적이고 혼동이 적습니다.

2배한 12는 1+2로 더하나요, 9를 빼나요?

두 방법 모두 결과는 3으로 같습니다. 룬 계산에서 2배한 값은 최대 18이므로 두 자리 결과에서 자릿수를 더하는 것과 9를 빼는 것이 항상 같습니다. 2배한 값이 9 이하라면 그대로 사용합니다.

합계가 10이면 유효하고 20이면 무효인가요?

10, 20, 30, 40처럼 모든 10의 배수가 유효한 합계입니다. 합계 자체가 10이어야 하는 것이 아니라 10으로 나눈 나머지가 0이어야 합니다. 이를 합계 mod 10=0이라고 씁니다.

룬을 통과하면 결제할 수 있는 카드인가요?

아닙니다. 룬 통과는 숫자열의 체크섬이 맞는다는 뜻입니다. 발급 여부, 활성 상태, 만료일, 보안코드, 소유권, 잔액과 거래 승인은 확인하지 않습니다. 실제 결제 가능 여부는 카드 발급사와 결제망의 승인 결과로 판단해야 합니다.

룬 알고리즘이 오류 위치도 알려 주나요?

체크섬이 맞지 않는다는 사실은 알려 주지만 어느 자리가 틀렸는지는 특정하지 못합니다. 하나의 나머지 값에 여러 오류 패턴이 대응할 수 있기 때문입니다. 사용자가 원본과 대조하거나 번호 전체를 다시 입력해야 합니다.

체크 디지트가 0인 경우도 있나요?

있습니다. 본문을 변환한 합계가 이미 10의 배수라면 부족한 값은 0이므로 체크 디지트도 0입니다. 생성 공식에 바깥쪽 mod 10을 한 번 더 적용하는 이유가 10 대신 0을 반환하기 위해서입니다.

룬 알고리즘 핵심 정리

룬 알고리즘은 숫자열 오른쪽에 붙는 한 자리 체크 디지트를 이용해 입력 오류를 검출합니다. 완성된 번호에서는 오른쪽 끝 체크 디지트를 그대로 두고, 오른쪽에서 두 번째 숫자부터 한 자리씩 건너 2배합니다. 결과가 10 이상이면 두 자릿수를 더하거나 9를 뺀 뒤 모든 값을 합칩니다. 합계가 10의 배수이면 검사를 통과합니다.

79927398713의 변환 합계는 70이므로 유효합니다. 체크 디지트가 없는 7992739871의 변환 합계는 67이고, 다음 10의 배수 70까지 필요한 숫자 3을 끝에 붙입니다. 생성 공식은 (10-(합계 mod 10)) mod 10입니다.

룬 공식은 모든 한 자리 대체 오류와 09↔90을 제외한 대부분의 인접 자리 교환을 찾아내지만, 모든 복수 오류를 검출하지는 않습니다. 또한 체크섬 검증일 뿐 암호화나 결제 승인이 아닙니다. 카드 PAN, IMEI처럼 실제 적용 대상마다 번호 길이·접두어·전처리 규칙이 다를 수 있으므로 해당 공식 규격과 함께 사용해야 합니다.

참고 자료