diff --git a/README.md b/README.md index eba9e5b..2748c78 100644 --- a/README.md +++ b/README.md @@ -99,17 +99,22 @@ Most cards do not even use a 3rd track, and is mostly un-used worldwide. | 9 | For assignment by national standards bodies *(next 3 digits are [ISO 3166-1](https://en.wikipedia.org/wiki/ISO_3166-1))* | ### Issuer Identification Number *(IIN)* -| Issuer | INN Range | PAN Digits | -| ------------------------- | ------------------------------- | ---------- | -| American Express | 34-37 | 15 | -| China Union Pay | 62 | 16-19 | -| Diners Club International | 36, 38, 39, 309, 300-3005 | 14 | -| Discover | 65, 644-649, 6011 622126-622925 | 16, 19 | -| JCB | 3528-3589 | 16 | -| Maestro | 50, 56-69 | 12-19 | -| Mastercard | 51-55, 2221-2720 | 16 | -| RuPay | 607 | 16 | -| Visa | 4 | 12, 16, 19 | +| Issuer | INN Range | PAN Digits | +| ------------------------- | -------------------------------- | ---------- | +| American Express | 34-37 | 15 | +| China Union Pay | 62 | 16-19 | +| Diners Club International | 36, 38, 39, 309, 300-3005 | 14 | +| Discover | 65, 644-649, 6011, 622126-622925 | 16, 19 | +| JCB | 3528-3589 | 16 | +| Maestro | 50, 56-69 | 12-19 | +| Mastercard | 51-55, 2221-2720 | 16 | +| RuPay | 607 | 16 | +| Visa | 4 | 12, 16, 19 | + +## Notes +The [Luhn Algorithm](https://en.wikipedia.org/wiki/Luhn_algorithm) or modulo-10 Algorithm *([example python code](./luhn_algo.py))* is used to determine the last digit of the account number, also known as the Check Number. + +This number should be divisible by 10, hence "modulo-10" ;) ## References - [Digital Card](https://en.wikipedia.org/wiki/Digital_card) diff --git a/luhn_algo.py b/luhn_algo.py new file mode 100644 index 0000000..6b5a86e --- /dev/null +++ b/luhn_algo.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# Luhn Algorithm Example - Developed by acidvegas in Python (https://git.acid.vegas/msr90) + +def modulus10(card_number: str) -> str: + ''' + Validate a card number using the Luhn Algorithm + + :param card_number: The card number to validate + ''' + + digits = [int(d) for d in card_number] + total_sum = 0 + reversed_digits = digits[::-1] + + for i in range(len(reversed_digits)): + digit = reversed_digits[i] + + if i % 2 != 0: + digit = digit * 2 + + if digit > 9: + digit -= 9 + + total_sum += digit + + check_digit = (10 - (total_sum % 10)) % 10 + full_card_number = card_number + str(check_digit) + + if (total_sum + check_digit) % 10 != 0: + raise ValueError('failed luhn check (non-divisible by 10)') + + return full_card_number + + +if __name__ == '__main__': + card_number = input('Enter your card number without the last digit:') + + if not card_number.isdigit(): + raise ValueError('invalid card number') + + print(f'Full card number: {modulus10(card_number)}')