Raymond's Notebook
日拱一卒无有尽,功不唐捐终入海
Luhn 算法

Luhn算法,也称为“模10”算法,是一种简单的校验算法,世界上大多数发卡机构,将该算法作为信用卡卡号的校验算法。能够通过该算法校验的卡号被认为是合规的卡号,但并不一定就是有效的卡号;无法通过验证的卡号,也不一定就是无效卡,这完全取决于发卡行是否使用该算法;有一点务必弄清楚,该算法的设计目的是防止意外输入错误,便于提前检查,而不是为了提供恶意攻击的工具。
一般信用卡由如下3部分组成:

  • 6位发卡行识别号码(IIN),也称银行识别码(BIN)
  • 最长12位的账户号码(Primary Account Number, PAN)
  • 1位校验码,以Luhn算法计算

Luhn算法 会通过校验码对一串数字进行验证,校验码通常会被加到这串数字的末尾处,从而得到一个完整的身份识别码。

我们以数字“7992739871”为例,计算其校验位,设校验位为X并添加至数列末位,即7992739871X:

  • 从校验位开始,从右往左,偶数位乘2(例如,7*2=14),然后将两位数字的个位与十位相加(例如,10:1+0=1,14:1+4=5);
  • 把得到的数字加在一起(本例中得到67);
  • 将数字的和取模10(本例中得到7),再用10去减(本例中得到3),得到校验位。

简单说来,该算法就是假设最后一位是校验位,然后从右到左,偶数位乘以2,将结果的个位和十位相加,
然后加上除开校验位之外所有奇数位,最终的和与10取模,然后用10减去该结果,其得的值应该等于校验位;如果不等,证明数字不符合该算法。
我们用 golang 来实现该算法:

func Luhn(creditCardCode string) bool {
    s := []rune(creditCardCode)
    if len(s) < 2 {
        return false
    }
    sum := 0
    for i, k := len(s)-1, 1; i >= 0; i, k = i-1, k+1 {
        val, _ := strconv.Atoi(string(s[i]))
        if k%2 == 0 {
            adr := val * 2
            a := adr / 10
            b := adr % 10
            sum = sum + (a + b)
        } else {
            if i < len(s)-1 {
                sum = sum + val
            }
        }
    }

    checkCode := 10 - (sum % 10)
    lastValue, _ := strconv.Atoi(string(s[len(s)-1]))
    return checkCode == lastValue
}

Luhn算法 除了被用于信用卡校验外,还被用于验证 移动设备识别码(IMEI),加拿大社会保险号,和其他共有领域需要进行数字验证的地方。该算法由IBM科学家 Hans Peter Luhn 创造。

参考资料: https://zh.wikipedia.org/wiki/Luhn%E7%AE%97%E6%B3%95