Luhn Formula, Mod 10, Modulus 10, Credit card & BPay Number Validation

Hans Peter Luhn the creator and original patent holder for the Modulus 10 Formula left us all a legacy. Just about every time you enter your credit card details online you will be subjected to the Luhn check. If you’re not, the website you are visiting is likely to be a little on the dodgy side.

Mod 10 as it’s commonly known is not the only check that a payment number goes through before validation of a payment occurs, it is only really usefull to check for typing errors and kids who think they might like to try random numbers. The real work of checking a payment number is going to be done by the bank or credit card gateway that is used by the merchant. When a check with mod 10 is done prior to sending a request to the final checker, it cuts down on millions of electronic requests to the many various payment providers and thus goes a long way to providing a smoother overall experience to users.

So now to the reason why I’m bothering to write about the Luhn Algorithm. The reason is not so much to do with the algorithm but with implimentation for bPay. bPay is a non-instant payment system popular in Australia where I live. With bPay you never have to give the store or service any payment details, they give you a unique payment number for either each user/account or for each unique transaction made for their business. A combination of both user and unique transaction is also possible. bPay numbers can become large due to the large amount of users who utilise the service and the amount of tracking the business decides to use. It’s common for CRN’s (Customer Reference Number) lengths of well over 20 digits. This is a rather large number and when considering doing calculations on it a few consideratons have to be made to ensure you get results. Your common off the shelf mod 10 program/script may not be able to cope with such large numbers due to the limitations of the data type programming language, or lack of forethough when it was written. So the reason as to why I have written this post is now ready to be revealed, I tried to use an off the shelf script in PHP for bPay validation and it failed…sometimes..

The script I initially utilised was written for credit card verification (16 digits in length), somewhat smaller than the 20+ digits I wanted to work with. After integrating the script and adding all the required functionality to the website shopping cart I was working on, everything seemed fine. CRN’s and check digits were getting produced during the checkout process and I was able to verify the CRN’s with some third party mod10 programs. It was only after producing the required 20 CRN’s during the bPay application process that any Issue was raised. The bank kindly sent an email in reply stating that some of the numbers didn’t check out. Admittidly it took a while to work out the issue, In my defence it was only every now and again the script would produce an incorrect check digit number. I rewrote the script a couple of times before it even occured to me to break the number up into chunks. Sure enough by processing the number in chunks it didn’t produce randomly incorrect numbers anymore. Further investigation showed that when dealing with larger numbers instead of producing an error message PHP would still provide an answer but the accuracy could be questionable. After a Google I found the PHP Integers page and the following

The size of an integer is platform-dependent, although a maximum value of about two billion is the usual value (that’s 32 bits signed). 64-bit platforms usually have a maximum value of about 9E18. PHP does not support unsigned integers. Integer size can be determined using the constant PHP_INT_SIZE, and maximum value using the constant PHP_INT_MAX since PHP 4.4.0 and PHP 5.0.5.

Two billion eh! that’s 2,000,000,000 in the short scale of things. At the command line on my test server

[brendon@hotchipsnsource]# php -r 'echo PHP_INT_MAX;'

produced exactly “2,147,483,647″.

That is not even enough to hold the 16 digit credit cards that the script was created for, so what is going on?

~to be continued.