From wikipedia:
It is not intended to be a cryptographically secure hash function; it was designed to protect against accidental errors, not malicious attacks. Most credit cards and many government identification numbers use the algorithm as a simple method of distinguishing valid numbers from mistyped or otherwise incorrect numbers.
def luhn_checksum(card_number):
def digits_of(n):
return [int(d) for d in str(n)]
digits = digits_of(card_number)
odd_digits = digits[-1::-2]
even_digits = digits[-2::-2]
checksum = 0
checksum += sum(odd_digits)
for d in even_digits:
checksum += sum(digits_of(d*2))
return checksum % 10
def is_luhn_valid(card_number):
return luhn_checksum(card_number) == 0
def calculate_luhn(partial_card_number):
check_digit = luhn_checksum(int(partial_card_number) * 10)
return check_digit if check_digit == 0 else 10 - check_digit
Using the random module, we can write a function that returns Luhn-valid numbers with a given amount of digits.
import random
def generate_card_number(number_of_digits):
partial_card_number = int("".join([str(random.randrange(10)) for i in range(number_of_digits - 1)]))
checksum = calculate_luhn(partial_card_number)
return int(str(partial_card_number) + str(checksum))
We can try out that function on the previous is_luhn_valid
method:
generate_card_number(16)
6979197319948772
is_luhn_valid(4083102477600833 )
True
Finally, we can also make a number of random tests of this sort.
[is_luhn_valid(generate_card_number(16)) for i in range(10000)] == [True]*10000
True