Maybe you wonder if your credit card has a correct number?
How to know that?
With the Luhn formula!
This is what we are going to see in this Luhn tutorial.
This algorithm can say if it is a good or a bad credit card number.
Indeed, for that we first of all have to reverse the complete number.
For example, the number to test is 1234567897.
Once reversed, we have 7987654321.
We can now add the double of pair series of this number.
In our case, we are going to double the number in bold: 79 87 65 43 21.
So we have now something like that:
7 18 8 14 6 10 4 6 2 2.
But now we need to add digits of each number:
7 + (1+8) + 8 + (1+4) + 6 + (1+0) + 4 + 6 + 2 + 2.
Finally the result is: 50.
To finish this Luhn test, we have to check if this final result can be divided by 10 without any rest.
So:
50 % 10 == 0
Our number is then validate by the Luhn algorithm.
Let’s see this in details with the code below:
Using the Luhn algorithm
main.c
/* main.c */
#include "h.h"
int main(int ac, char *av[])
{
t_luhn b;
init(ac, av, &b);
return 0;
}
misc.c
/* misc.c */
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include "h.h"
void init(int ac, char *av[], t_luhn *b)
{
if (ac < 2)
{
printf("Usage: ./luhn-algo [number]\n");
exit(1);
}
check_number(av[1]);
b->classic = av[1];
b->result = 0;
b->len = strlen(b->classic);
check_size(b);
reverse_str(b);
calculate_result(b);
debug(b);
if (b->rev != NULL)
free(b->rev);
else
{
fprintf(stderr, "Error: %s\n", strerror(errno));
exit(1);
}
}
void find_luhn(t_luhn *b)
{
if (b->result % 10 == 0)
printf("GOOD: the code %s is a valid Luhn number!\n", b->classic);
else
printf("BAD: the code %s is not a valid Luhn number!\n", b->classic);
}
void check_size(t_luhn *b)
{
if (b->len < 16)
b->try = 1;
else
b->try = 0;
}
void debug(t_luhn *b)
{
printf("\n===== START =====\n\n");
printf("Result = %d\n", b->result);
find_luhn(b);
printf("\n===== END =====\n\n");
}
int is_pair(int i)
{
if (i % 2 == 0)
return 0;
return 1;
}
void reverse_str(t_luhn *b)
{
unsigned int i;
b->rev = malloc(sizeof(*b->rev) * b->len);
if (b->rev == NULL)
{
fprintf(stderr, "Error: %s\n", strerror(errno));
exit(1);
}
i = 0;
while (i < b->len)
{
b->rev[i] = b->classic[b->len - i - 1];
++i;
}
}
void calculate_result(t_luhn *b)
{
unsigned int i;
int newVal[10] = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9};
i = 0;
while (i < b->len)
{
if (is_pair(i))
b->result += newVal[b->rev[i] - 48];
else
b->result += b->rev[i] - 48;
++i;
}
}
void check_number(char *av)
{
unsigned int i;
i = 0;
if (av[0] == '-')
{
i = 1;
}
while (i < strlen(av))
{
if (av[i] < 48 || av[i] > 57)
{
fprintf(stderr, "Error: %s\n", "Allowed characters: [0-9]");
exit(1);
}
++i;
}
}
h.h
#ifndef H_H_
#define H_H_
/**
* Structure
*/
typedef struct luhn
{
char *classic;
char *rev;
int result;
unsigned len;
int try;
} t_luhn;
/**
* Prototype
*/
void init(int ac, char *av[], t_luhn *b);
void debug(t_luhn *b);
void calculate_result(t_luhn *b);
void check_number(char *av);
void reverse_str(t_luhn *b);
void check_size(t_luhn *b);
void find_luhn(t_luhn *b);
#endif /* H_H_ */
Compiling
$ gcc main.c misc.c -o luhn-algo ; ./luhn-algo 1234567897
Output
===== START =====
Result = 50
GOOD: the code 1234567897 is a valid Luhn number!
===== END =====
Well done.