メニュー

Luhn アルゴリズムとは: 1 桁の検算で誤入力を防ぐ仕組み

Luhn アルゴリズムの計算手順を手計算で追い、なぜ隣り合う数字の入れ替えを見つけられるのか、どこで見逃すのかを解説します。実装時の順序と限界も整理します。

公開日

  • チェックディジット
  • 決済

Luhn アルゴリズムは、カード番号の最後の 1 桁が正しく計算されているかを確かめるための、公開された単純な検算手順です。1950 年代に IBM の Hans Peter Luhn が考案し、その後 ISO/IEC 7812 を通じてカード番号のチェックディジットとして広く使われるようになりました。この記事では、計算の中身を手順に分解し、手計算で一度追い、実装で気をつける点と、この方法では防げない範囲までを説明します。

末尾の 1 桁は何のためにあるのか?

長い数字列を人が入力すれば、必ずどこかで打ち間違いが起きます。そのすべてを発行会社に問い合わせるのは無駄が多すぎます。そこで、番号そのものに自己検算の仕掛けを埋め込み、明らかに壊れた入力を手前で止めることにしました。その仕掛けがチェックディジットです。

番号の最後の 1 桁は、それより前のすべての桁から機械的に決まります。つまり利用者が適当に数字を打ち込んだ場合、最後の 1 桁が合う確率はおよそ 10 分の 1 です。この確率を下げるだけでも、入力欄の体験は大きく変わります。

計算手順を言葉で追う

手順は次のとおりです。まず右端から数えて 2 桁目を起点にし、そこから 1 桁おきに数字を 2 倍します。2 倍した結果が 2 桁になったら、その 2 桁を足して 1 桁に畳みます。18 なら 1 と 8 を足して 9、10 なら 1 と 0 を足して 1 です。2 倍しなかった桁はそのまま加算します。すべてを合計し、その値が 10 で割り切れれば、番号は検算を通過します。

チェックディジットを新しく作るときは、同じ計算を「最後の 1 桁を除いた部分」に対して行い、合計を 10 の倍数にするために不足する数を求めます。これが末尾に置く数字になります。検算と生成は同じ算術の裏表であり、片方を理解すればもう片方も自然に導けます。

手計算で確かめる

具体的な数字で一度追ってみます。ここでは仮に 8 桁の番号の先頭 7 桁を 4、5、3、2、0、1、5 とします。右端の 5 から数えて 2 桁目、つまり右から 2 番目の 1 が最初の 2 倍対象です。右から順に 2 倍の対象を拾うと、1、2、5、4 が該当します。

それぞれを 2 倍して 1 桁に畳むと、1 は 2、2 は 4、5 は 10 なので 1、4 は 8 になります。2 倍しなかった桁は 5、3、0 のままです。計算の全体を表にすると次のようになります。

元の桁 4 5 3 2 0 1 5
2 倍するか はい いいえ はい いいえ はい いいえ はい
加算する値 8 5 6 2 0 1 1

合計は 1 足す 4 足す 6 足す 8 足す 4 足す 5 足す 0 足す 1 で 29 です。10 の倍数にするには 1 が足りません。したがって末尾のチェックディジットは 1 となり、番号全体は 4 5 3 2 0 1 5 1 という 8 桁になります。落ち着いて追えば、電卓なしでも 1 分とかかりません。

隣り合う数字の入れ替えはなぜ見つかるのか?

この手順の利点は、単純な打ち間違いの多くを検出できる点にあります。とくに「隣り合う 2 桁を逆に入力した」という誤りに対して働きます。1 桁おきに重みを変えているため、隣り合う桁は片方が 2 倍され、もう片方がされない関係にあります。順序を入れ替えると、どの桁が 2 倍されるかが入れ替わり、合計が変わります。結果として 10 で割り切れなくなり、誤りが表面化します。

ただし万能ではありません。入れ替えても合計が変わらない組み合わせが存在します。代表例が 0 と 9、またはその重みの組み合わせで、片方を 2 倍して畳んだ値がもう片方と一致してしまう場合です。こうした例は見逃されます。加えて、同じ桁を 2 回打った場合や、まったく別の数字に置き換わった場合の検出率は 10 分の 1 程度にとどまります。

Luhn アルゴリズムで検出できないもの

検算を通過したからといって、その番号が実在することにはなりません。計算方法は公開されているので、条件を満たす番号はいくらでも作れます。誰かが他人のカード番号を 1 桁書き換えた場合も、書き換えた桁に合わせて末尾を直せば検算は通ってしまいます。

同じ理由で、検算は不正利用への対策にもなりません。防げるのは事故による打ち間違いだけで、意図的な偽装は素通りします。番号が有効かどうかの最終判断は、発行会社への照会、つまりオーソリゼーションの応答でしか下せません。この役割分担を混同すると、セキュリティ上の誤った前提を置くことになります。

開発者向け: 検証の順序と落とし穴

実装では、検証の順序を固定することがもっとも重要です。長さの確認、使用可能な文字の確認、そして最後にチェックディジットの計算、という流れにします。順序を入れ替えると、たとえば空文字や記号混じりの入力に対して計算処理が走り、想定外の例外や誤ったエラーメッセージにつながります。

桁数の判定では、1 つの値だけを正解にしないでください。国際ブランドごとに長さが異なるうえ、規格上の上限は 19 桁あり、13 桁や 15 桁の番号も実在します。長さを先に固定してしまうと、本来受け入れるべき入力を弾きます。まず桁数の範囲で絞り、そのうえでブランドごとの規則を当てる順序が安全です。

計算の途中で桁を文字列として扱うか数値として扱うかも判断が必要です。2 倍した結果を 1 桁に畳む処理を忘れると、合計がずれて正しい番号を拒否します。テストを書くときは、検算を通る番号と通らない番号を必ず 1 件ずつ用意し、境界として最短桁と最長桁も加えておきましょう。なお、検算を通るように作った番号は、構造としては妥当でも実際には発行されていない値です。実在のカードとして扱わないでください。番号の組み立て方を体系的に理解したい場合は カード番号の構成を読み解く を、実装全体の流れは カード番号検証の考え方 を参照してください。

次のステップ

まず、自分の手元で 1 件だけ手計算をして、その結果を実装の出力と突き合わせてください。計算過程を自分の目で追っておくと、実装がずれたときに原因を特定しやすくなります。次に、検算を「実在性の証明」として扱っていない箇所がないかを点検します。用途が入力ミスの検出に限定されていることを確認できれば、この仕組みを正しく使いこなせています。手元で複数の番号を用意したいときは、テスト用クレジットカード番号生成 で桁数とブランドを指定して生成できます。

続けて読む

テスト用クレジットカード番号生成の関連記事