Контрольная сумма СС. Алгоритм Luhn.

Forum Library

Professional
Messages
1,168
Reputation
195
Reaction score
491
Points
83
Кратко здесь - http://ru.wikipedia.org/wiki/Алгоритм_Луна


Информация скорее полезная для разработчиков, чем обычных пользователей. Алгоритм вычисления контрольной суммы номера пластиковых карт в соответствии со стандартом ISO/IEC 7812.

Алгоритм Луна или формула Луна — алгоритм вычисления контрольной цифры, получивший широкую популярность. Он используется, в частности, при первичной проверке номеров банковских пластиковых карт, номеров социального страхования в США и Канаде. Алгоритм был разработан сотрудником компании «IBM» Хансом Петером Луном и запатентован (патент США № 2 950 048) в 1960 году.

В настоящее время алгоритм находится в общественном достоянии. Как уже говорилось ранее, контрольные цифры вообще и алгоритм Луна в частности предназначены для защиты от случайных ошибок, а не преднамеренных искажений данных.

Алгоритм Луна позволяет выявить все одиночные ошибки и практически все перестановки соседних чисел в числовых последовательностях любой длины (не выявляются только перестановки нуля и девятки: «09» вместо «90» и наоборот). Более сложные алгоритмы (например, алгоритм Верхоффа) позволяют выявить большее количество ошибок.

Так как алгоритм оперирует цифрами в обратном порядке (справа налево), нули в начале числа никак не влияют на значение контрольной цифры. Таким образом, системы, дополняющие проверяемое число нулями слева до определенной длины (например, «1234» до «0000001234»), могут проводить проверку как до дополнения, так и после него.

Алгоритм Луна работает только с последовательностями десятичных цифр. Несколько модифицированный вариант, известный как «алгоритм Луна по модулю N», позволяет расширить диапазон проверяемых символов.

Начиная со второго числа справа через 1 (то есть 2,4,6,8,10…) делается проверка: если х*2>9 то из произведения вычитается 9, если х*2≤9 то произведение оставляем без изменения.

Code:
4  5  6  1     2  6  1  2     1  2  3  4     5  4  6  4
8     12       4     2        2     6        10    12
8     3        4     2        2     6        1     3

После все числа складываются.

Code:
8+5+3+1 + 4+6+2+2 + 2+2+6+4 + 1+4+3+4 = 57

Полученная сумма должна быть кратна 10 (40,50,60,70…)

В примере: последнее число это контрольная цифра, для того чтобы номер был верен в соответствии с алгоритмом Луна, контрольная цифра должна быть равна 7.

Code:
4  5  6  1     2  6  1  2     1  2  3  4     5  4  6  7
8     12       4     2        2     6        10    12
8     3        4     2        2     6        1     3

Code:
8+5+3+1 + 4+6+2+2 + 2+2+6+4 + 1+4+3+7 = 60

Алгоритм вычисления контрольной суммы:

Num[1..N] - номер карты, Num[N] - контрольная сумма.

Code:
sum = 0
 for i = 1 to N-1 do
   if (i mod 2 = 0) then
     p = Num[i]
   else
     p = 2*Num[i]
   if (p > 9) then 
     p = p - 9
   sum = sum + p
 sum = sum mod 10
 //дополнение до 10
 sum = (10 - sum) mod 10
 Num[N] = sum

==================
Исходный код (PHP):

Code:
<?

  function validatecard($cardnumber) {
    $cardnumber=preg_replace("/\D|\s/", "", $cardnumber);  # strip any non-digits
    $cardlength=strlen($cardnumber);
    $parity=$cardlength % 2;
    $sum=0;
    for ($i=0; $i<cardlength>9) $digit=$digit-9;
      $sum=$sum+$digit;
    }
    $valid=($sum%10==0);
    return $valid;
  }
?>


---------- Post added at 04:45 ---------- Previous post was at 04:45 ----------

Code:
код на *.js :

/* cc validation start */

var Cards = new makeArray(8);
Cards[0] = new CardType("MasterCard", "51,52,53,54,55", "16");
var MasterCard = Cards[0];
Cards[1] = new CardType("VisaCard", "4", "13,16");
var VisaCard = Cards[1];
Cards[2] = new CardType("AmExCard", "34,37", "15");
var AmExCard = Cards[2];
Cards[3] = new CardType("DinersClubCard", "30,36,38", "14");
var DinersClubCard = Cards[3];
Cards[4] = new CardType("DiscoverCard", "6011", "16");
var DiscoverCard = Cards[4];
Cards[5] = new CardType("enRouteCard", "2014,2149", "15");
var enRouteCard = Cards[5];
Cards[6] = new CardType("JCBCard", "3088,3096,3112,3158,3337,3528", "16");
var JCBCard = Cards[6];
var LuhnCheckSum = Cards[7] = new CardType();



function CheckCardNumber(form) {
var tmpyear;
if (form.payCCNumber.value.length == 0) {
alert("Please enter a Card Number.");
form.payCCNumber.focus();
return;
}
if (form.payCCYear.value.length == 0) {
alert("Please enter the Expiration Year.");
form.payCCYear.focus();
return;
}
if (form.payCCYear.value > 96)
tmpyear = "19" + form.payCCYear.value;
else if (form.payCCYear.value < 21)
tmpyear = "20" + form.payCCYear.value;
else {
alert("The Expiration Year is not valid.");
return;
}
tmpmonth = form.payCCMonth.options[form.payCCMonth.selectedIndex].value;
// The following line doesn't work in IE3, you need to change it
// to something like "(new CardType())...".
// if (!CardType().isExpiryDate(tmpyear, tmpmonth)) {
if (!(new CardType()).isExpiryDate(tmpyear, tmpmonth)) {
alert("This card has already expired.");
return;
}
card = form.payCCType.options[form.payCCType.selectedIndex].value;
var retval = eval(card + ".checkCardNumber(\"" + form.payCCNumber.value +
"\", " + tmpyear + ", " + tmpmonth + ");");
cardname = "";
if (retval)

return true;

// comment this out if used on an order form
//alert("This card number appears to be valid.");


else {
// The cardnumber has the valid luhn checksum, but we want to know which
// cardtype it belongs to.
for (var n = 0; n < Cards.size; n++) {
if (Cards[n].checkCardNumber(form.payCCNumber.value, tmpyear, tmpmonth)) {
cardname = Cards[n].getCardType();
break;
}
}
if (cardname.length > 0) {
alert("This looks like a " + cardname + " number, not a " + card + " number.");
}
else {
alert("This card number is not valid.");
}
}
}
/************************************************** ***********************\
Object CardType([String cardtype, String rules, String len, int year, 
int month])
cardtype : type of card, eg: MasterCard, Visa, etc.
rules : rules of the cardnumber, eg: "4", "6011", "34,37".
len : valid length of cardnumber, eg: "16,19", "13,16".
year : year of expiry date.
month : month of expiry date.
eg:
var VisaCard = new CardType("Visa", "4", "16");
var AmExCard = new CardType("AmEx", "34,37", "15");
\************************************************* ************************/
function CardType() {
var n;
var argv = CardType.arguments;
var argc = CardType.arguments.length;

this.objname = "object CardType";

var tmpcardtype = (argc > 0) ? argv[0] : "CardObject";
var tmprules = (argc > 1) ? argv[1] : "0,1,2,3,4,5,6,7,8,9";
var tmplen = (argc > 2) ? argv[2] : "13,14,15,16,19";

this.setCardNumber = setCardNumber; // set CardNumber method.
this.setCardType = setCardType; // setCardType method.
this.setLen = setLen; // setLen method.
this.setRules = setRules; // setRules method.
this.setExpiryDate = setExpiryDate; // setExpiryDate method.

this.setCardType(tmpcardtype);
this.setLen(tmplen);
this.setRules(tmprules);
if (argc > 4)
this.setExpiryDate(argv[3], argv[4]);

this.checkCardNumber = checkCardNumber; // checkCardNumber method.
this.getExpiryDate = getExpiryDate; // getExpiryDate method.
this.getCardType = getCardType; // getCardType method.
this.isCardNumber = isCardNumber; // isCardNumber method.
this.isExpiryDate = isExpiryDate; // isExpiryDate method.
this.luhnCheck = luhnCheck;// luhnCheck method.
return this;
}

/************************************************** ***********************\
boolean checkCardNumber([String cardnumber, int year, int month])
return true if cardnumber pass the luhncheck and the expiry date is
valid, else return false.
\************************************************* ************************/
function checkCardNumber() {
var argv = checkCardNumber.arguments;
var argc = checkCardNumber.arguments.length;
var cardnumber = (argc > 0) ? argv[0] : this.cardnumber;
var year = (argc > 1) ? argv[1] : this.year;
var month = (argc > 2) ? argv[2] : this.month;

this.setCardNumber(cardnumber);
this.setExpiryDate(year, month);

if (!this.isCardNumber())
return false;
if (!this.isExpiryDate())
return false;

return true;
}
/************************************************** ***********************\
String getCardType()
return the cardtype.
\************************************************* ************************/
function getCardType() {
return this.cardtype;
}
/************************************************** ***********************\
String getExpiryDate()
return the expiry date.
\************************************************* ************************/
function getExpiryDate() {
return this.month + "/" + this.year;
}
/************************************************** ***********************\
boolean isCardNumber([String cardnumber])
return true if cardnumber pass the luhncheck and the rules, else return
false.
\************************************************* ************************/
function isCardNumber() {
var argv = isCardNumber.arguments;
var argc = isCardNumber.arguments.length;
var cardnumber = (argc > 0) ? argv[0] : this.cardnumber;
if (!this.luhnCheck())
return false;

for (var n = 0; n < this.len.size; n++)
if (cardnumber.toString().length == this.len[n]) {
for (var m = 0; m < this.rules.size; m++) {
var headdigit = cardnumber.substring(0, this.rules[m].toString().length);
if (headdigit == this.rules[m])
return true;
}
return false;
}
return false;
}

/************************************************** ***********************\
boolean isExpiryDate([int year, int month])
return true if the date is a valid expiry date,
else return false.
\************************************************* ************************/
function isExpiryDate() {
var argv = isExpiryDate.arguments;
var argc = isExpiryDate.arguments.length;

year = argc > 0 ? argv[0] : this.year;
month = argc > 1 ? argv[1] : this.month;

if (!isNum(year+""))
return false;
if (!isNum(month+""))
return false;
today = new Date();
expiry = new Date(year, month);
if (today.getTime() > expiry.getTime())
return false;
else
return true;
}

/************************************************** ***********************\
boolean isNum(String argvalue)
return true if argvalue contains only numeric characters,
else return false.
\************************************************* ************************/
function isNum(argvalue) {
argvalue = argvalue.toString();

if (argvalue.length == 0)
return false;

for (var n = 0; n < argvalue.length; n++)
if (argvalue.substring(n, n+1) < "0" || argvalue.substring(n, n+1) > "9")
return false;

return true;
}

/************************************************** ***********************\
boolean luhnCheck([String CardNumber])
return true if CardNumber pass the luhn check else return false.
Reference: ********www.ling.nwu.edu/~sburke/pub/luhn_lib.pl
\************************************************* ************************/
function luhnCheck() {
var argv = luhnCheck.arguments;
var argc = luhnCheck.arguments.length;

var CardNumber = argc > 0 ? argv[0] : this.cardnumber;

if (! isNum(CardNumber)) {
return false;
}

var no_digit = CardNumber.length;
var oddoeven = no_digit & 1;
var sum = 0;

for (var count = 0; count < no_digit; count++) {
var digit = parseInt(CardNumber.charAt(count));
if (!((count & 1) ^ oddoeven)) {
digit *= 2;
if (digit > 9)
digit -= 9;
}
sum += digit;
}
if (sum % 10 == 0)
return true;
else
return false;
}

/************************************************** ***********************\
ArrayObject makeArray(int size)
return the array object in the size specified.
\************************************************* ************************/
function makeArray(size) {
this.size = size;
return this;
}

/************************************************** ***********************\
CardType setCardNumber(cardnumber)
return the CardType object.
\************************************************* ************************/
function setCardNumber(cardnumber) {
this.cardnumber = cardnumber;
return this;
}

/************************************************** ***********************\
CardType setCardType(cardtype)
return the CardType object.
\************************************************* ************************/
function setCardType(cardtype) {
this.cardtype = cardtype;
return this;
}

/************************************************** ***********************\
CardType setExpiryDate(year, month)
return the CardType object.
\************************************************* ************************/
function setExpiryDate(year, month) {
this.year = year;
this.month = month;
return this;
}

/************************************************** ***********************\
CardType setLen(len)
return the CardType object.
\************************************************* ************************/
function setLen(len) {
// Create the len array.
if (len.length == 0 || len == null)
len = "13,14,15,16,19";

var tmplen = len;
n = 1;
while (tmplen.indexOf(",") != -1) {
tmplen = tmplen.substring(tmplen.indexOf(",") + 1, tmplen.length);
n++;
}
this.len = new makeArray(n);
n = 0;
while (len.indexOf(",") != -1) {
var tmpstr = len.substring(0, len.indexOf(","));
this.len[n] = tmpstr;
len = len.substring(len.indexOf(",") + 1, len.length);
n++;
}
this.len[n] = len;
return this;
}

/************************************************** ***********************\
CardType setRules()
return the CardType object.
\************************************************* ************************/
function setRules(rules) {
// Create the rules array.
if (rules.length == 0 || rules == null)
rules = "0,1,2,3,4,5,6,7,8,9";

var tmprules = rules;
n = 1;
while (tmprules.indexOf(",") != -1) {
tmprules = tmprules.substring(tmprules.indexOf(",") + 1, tmprules.length);
n++;
}
this.rules = new makeArray(n);
n = 0;
while (rules.indexOf(",") != -1) {
var tmpstr = rules.substring(0, rules.indexOf(","));
this.rules[n] = tmpstr;
rules = rules.substring(rules.indexOf(",") + 1, rules.length);
n++;
}
this.rules[n] = rules;
return this;
}
 
Top