読者です 読者をやめる 読者になる 読者になる

mo-fu note

技術のこととか色々書きます

クレジットカード番号の入力誤り確認について

クレジットカードの入力フォームを作る時に使ったライブラリで、 DinersClubの番号が対応されていなかったので修正してみた。

github.com

修正の検証で、試しにDinersClubの番号を適当に入力したらエラーになった。

テスト用のカード番号 3056 930902 5904 だとエラーにならないけど、 3056 930902 5914 にすると何でエラーになるんだろう...? と少し考えた後に、 クレジットカード番号の入力誤りチェックにはLuhnアルゴリズムが使われていることを思いだした。

クレジットカードの番号は ISO/IEC 7812 で仕様が決められていて、 1から6桁目までは発行者を識別するための番号、 最後の1桁をチェックデジット(誤り確認のための数字)として使用している。

Luhnアルゴリズム

  1. 一の位から数えて奇数番目の場合はそのまま、偶数番目の場合は数を2倍する
  2. 2倍にした偶数番目の数が10以上の場合は、その各桁を足して1桁にする
    • 例) 18 の 場合は 1 + 8 = 9 とする
  3. 得られた桁の数を全部足す
  4. 10で割り切れれば正当な番号

チェックデジットのサンプル

WEB+DB PRESS Vol.76 のWeb決済入門で紹介されていた、 サンプルを参考にして実際にテストしてみた。

WEB+DB PRESS Vol.76

WEB+DB PRESS Vol.76

  • 作者: 五十嵐啓人,伊野亘輝,近藤宇智朗,渡邊恵太,須藤耕平,中島聡,A-Listers,はまちや2,川添貴生,片山育美,池田拓司,濱崎健吾,佐藤太一,曾川景介,久保渓,門脇恒平,登尾徳誠,伊藤直也,mala,後藤秀宣,若原祥正,奥野幹也,大林源,WEB+DB PRESS編集部
  • 出版社/メーカー: 技術評論社
  • 発売日: 2013/08/24
  • メディア: 大型本
  • この商品を含むブログを見る

Luhnアルゴリズムで番号を検証

class Luhn
  def self.check_number(number)
    reversed_numbers = number.reverse
    number_characters = reversed_numbers.chars
    number_characters.each_with_index.map{ |ch, index|
      # 0番目から数えて偶数番目の時(1桁目から数えた場合は奇数になる)
      if index.even?
        ch.to_i
      else
        x2 = ch.to_i * 2
        (x2) % 10 + (x2) / 10
      end
    }.inject(:+) % 10 == 0
  end
end

テストを書いて実行してみる

require 'test/unit'
require_relative 'luhn'

class TC_Luhn < Test::Unit::TestCase
  def test_luhn_valid
    assert_equal(Luhn.check_number("30569309025904"), true)
  end

  def test_luhn_invalid
    assert_equal(Luhn.check_number("30569309025914"), false)
  end
end

30569309025904 はテスト用のカード番号で、 30569309025914 はわざと番号を間違えたものです。

実行結果

ruby test_luhn.rb

Loaded suite test_luhn
Started
..

Finished in 0.000691 seconds.
-------------------------------------------------------------------------------------------------------------------------------
2 tests, 2 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
-------------------------------------------------------------------------------------------------------------------------------
2894.36 tests/s, 2894.36 assertions/s

実行結果を見ると 30569309025914 はカード番号を間違えているので、 Luhn.check_number() の返り値は false となる。

参考文献・参考サイト