Luhn算法(Luhn algorithm),也称为“模10”(Mod 10)算法,是一种简单的校验和算法,一般用于验证身份识别码,例如发卡行识别码、国际移动设备辨识码(IMEI),美国国家提供商标识号码,或是加拿大社会保险号码。该算法由IBM科学家Hans Peter Luhn创造,专利于1954年1月6日申请,1960年8月23日颁证,美国专利号2950048。
该算法现已属于公有领域并得到了广泛的应用,例如ISO/IEC 7812-1。它不是一种安全的加密哈希函数,设计它的目的只是防止意外出错而不是恶意攻击。1
描述Luhn算法会通过校验码对一串数字进行验证,校验码通常会被加到这串数字的末尾处,从而得到一个完整的身份识别码。
我们以数字“7992739871”为例,计算其校验位:
从校验位开始,从右往左,偶数位乘2(例如,7*2=14),然后将两位数字的个位与十位相加(例如,10:1+0=1,14:1+4=5);
把得到的数字加在一起(本例中得到67);
将数字的和取模10(本例中得到7),再用10去减(本例中得到3),得到校验位。
|| ||
另一种方法是:
从校验位开始,从右往左,偶数位乘2,然后将两位数字的个位与十位相加;
计算所有数字的和(67);
乘以9(603);
取其个位数字(3),得到校验位。
优点和缺点Luhn算法将检测任何单位错误,以及几乎所有相邻数字的转置。但是,它不会检测到两位数序列09到90的转置(反之亦然)。它将检测10个可能的双误差中的7个(它不会检测到22↔55,33↔66或44↔77)。
其他更复杂的校验位算法(例如Verhoeff算法和Damm算法)可以检测更多的转录错误。 Luhn mod N算法是支持非数字字符串的扩展。
因为算法以从右到左的方式对数字进行操作,并且零位仅在它们导致位置偏移时影响结果,所以零填充数字串的开头不会影响计算。因此,填充到特定位数的系统(例如,通过将1234转换为0001234)可以在填充之前或之后执行Luhn验证并获得相同的结果。
在0到奇数长度之前,可以从左到右而不是从右到左处理数字,使奇数位数加倍。
该算法出现于美国专利2中,用于计算校验和的手持式机械设备。因此需要相当简单。该装置通过机械手段获得了模数10。替换数字,即double和reduce过程的结果,不是机械地产生的。相反,数字在机器的主体上以其置换顺序标记。
应用实例Pseudo-Code function checkLuhn(string purportedCC) { int sum := integer(purportedCC[length(purportedCC)-1]) int nDigits := length(purportedCC) int parity := nDigits modulus 2 for i from 0 to nDigits - 2 { int digit := integer(purportedCC[i]) if i modulus 2 = parity digit := digit × 2 if digit > 9 digit := digit - 9 sum := sum + digit } return (sum modulus 10) = 0 }Bash#!/bin/bash strip_last() { echo ${1:$((${#1}-1)):1}} NUMBER=$1NUM_DIGITS=${#NUMBER}ODD_INDEX_MODIFIER=$(( ${NUM_DIGITS} % 2 ))INDEX=1TOTAL_NON_CHECK=0while read -n1 DIGIT; do # read 1 character if [ $(( (${ODD_INDEX_MODIFIER} + ${INDEX}) % 2 )) -eq 0 ]; then # Even index relative to least significant digit LSD TMP=$(( ${DIGIT} * 2 )) if [ ${TMP} -ge 10 ]; then TMP=$(( ${TMP} - 9)) fi TOTAL_NON_CHECK=$((${TOTAL_NON_CHECK} + ${TMP})) else TOTAL_NON_CHECK=$((${TOTAL_NON_CHECK} + ${DIGIT})) fi INDEX=$((${INDEX} + 1))done Java public static boolean check(int[] digits) { int sum = 0; int length = digits.length; for (int i = 0; i 9 ? digit - 9 : digit; } return sum % 10 == 0; }JavaScriptfunction luhn(num) {num = (num + '').replace(/\D+/g, '').split('').reverse();if (!num.length) {return false;}var total = 0, i;for (i = 0; i 4 ? 9 : 0) : num[i];}return (total % 10) == 0;}Pythondef checkLuhn(purportedCC=''): sum_ = 0 parity = len(purportedCC) % 2 for i, digit in enumerate([int(x) for x in purportedCC]): if i % 2 == parity: digit *= 2 if digit > 9: digit -= 9 sum_ += digit return sum_ % 10 == 0本词条内容贡献者为:
王伟 - 副教授 - 上海交通大学