Packages

Library for categorizing and validating credit card numbers.

Current section

Files

Jump to
cnum lib validator.ex
Raw

lib/validator.ex

defmodule Cnum.Validator do
@moduledoc false
# Validator validates a credit card number through the Luhn algorithm.
# Test credit card numbers are valid by default even if they would not pass the Luhn check.
require Integer
@test_cards [
2223000048400011,
2223003122003222,
2223520043560014,
30569309025904,
3530111333300000,
3566002020360505,
371449635398431,
378282246310005,
378734493671000,
38520000023237,
4000056655665556,
4012888888881881,
4111111111111111,
4222222222222,
4242424242424242,
5105105105105100,
5200828282828210,
5555555555554444,
5610591081018250,
6011111111111117,
6011000990139424,
6200000000000005
]
@doc false
def validate(number) do
if Enum.member?(@test_cards, number),
do: true, else: luhn_check(number)
end
# -------------------------------------------------- #
defp luhn_check(number) do
[ check_digit | remaining_digits ] = Integer.digits(number) |> Enum.reverse
luhn_sum(remaining_digits) |> mod_10_check(check_digit)
end
defp luhn_sum(digits, index \\ 0, acc \\ 0)
defp luhn_sum([], _index, acc), do: acc
defp luhn_sum([digit | tail], index, acc) when Integer.is_odd(index),
do: luhn_sum(tail, index + 1, acc + digit)
defp luhn_sum([digit | tail], index, acc) when Integer.is_even(index),
do: luhn_sum(tail, index + 1, acc + partial_sum(digit * 2))
defp mod_10_check(digits_sum, check_digit) do
Integer.mod((digits_sum + check_digit), 10) == 0
end
defp partial_sum(number) when number > 9 do
Integer.digits(number) |> Enum.sum()
end
defp partial_sum(number), do: number
end