身份证和条形码中的校验码

通常校验码是指通过计算得出的一组数的最后一位或几位,例如身份证和条形码的最后一位,用来检验是否出现了输入错误。在数据传输的时候,一般也会在数据的末尾加上几位校验位来判断传输的数据是否有误。

一般说来,人类容易犯的常见输入错误有:

  • 输错某一位:1 → 2
  • 颠倒相邻两位顺序:12 → 21
  • 输错相邻的两位相同数字:33 → 44
  • 跳跃错位:456 → 645

而一个好的校验码方案能够检测出以上大多数以上的输入错误。

一个有效的校验位方案是将所有数位相加然后取被 10 除的余数,如果其中的一位错了,那么总和就会变化,相应的校验码就会改变,所以这样的方案能够检测出所有输错一位的情形。但是对于颠倒相邻两位的错误,这个方案却无能为力,因为数字的总和不会变化。

条形码的校验位

给每一位加一个权,然后计算加权的总和模 10 是上述方法的一个改进。如EAN条形码的校验位计算就是给偶数位乘上 3 的权求和,然后加上奇数位的和,最后取模 10 的值。这种方法也能检测出所有输错某一位可能性,也能检测到大部分颠倒相邻两位的情况。

如果设颠倒顺序的两位分别是 a, b,那么 a 和 b 一定不等,假设产生的校验码是相同的:
\[3a+b \equiv 3b+a \pmod{10}\]
等价于
\[2(a-b) \equiv 0 \pmod{10}\]
所以 a – b 是 5 的倍数。因此这种方法不能检测出相差 5 的相邻两位(如 1 和 6)输入颠倒的错误。

身份证的校验位

与条形码不同,身份证的校验位有可能出现“X”,因此有 11 种可能,能够识别的错误相比较而言也更多。其计算方法也是计算加权的和,设身份证的第 i 位为 d(i),则身份证的第 18 位可参照下面计算:
先根据前 17 位算出
\[S=\sum_{i=1}^{17}2^{18-i}d(i)\]
然后算出 12 – S 模 11 的值就是身份证的第 18 位,如果结果是 10,就用“X”替代。

身份证的校验位能完全检测出第二种颠倒顺序的输入错误。假设输入中颠倒了相邻两位 a, b 的顺序而校验码却没有改变,就有
\[2^{m+1}a+2^{m}b \equiv 2^{m}a+2^{m+1}b \pmod{11}\\ (a-b)2^{m} \equiv 0 \pmod{11}\]
这说明 11 能整除 a – b,这显然是不可能的。

不少要求填写身份证的网站并不会连接数据库验证姓名和身份证号是否相符,这时候只要用一个出生日期“伪造”一个校验码正确的身份证号,就能通过注册了。

火车票上印刷的身份证号码出于隐私的考虑隐去了出生月日的四位。由于最后一位校验码的存在,其实只有三十三四种可能性存在,这其实是很不安全的,所以建议大家买个碎纸机,用完就把火车票扔进碎纸机里去,o(╯□╰)o。

One thought on “身份证和条形码中的校验码

  1. […] 首先,我们注意到下面的一串 13 位数字,这是我们要编码的内容。前三位 693 代表是中国大陆生产(690 – 699 都是保留给中国大陆的),紧接着有四位的制造商代码和五位的产品代码,最后一位是校验码,用来检验条码是否有输入错误,详细说明请参考身份证和条形码中的校验码。大家很容易猜到,条形码的存储的信息是通过粗细不同的黑白条纹的不同排列组合来实现的,事实也的确如此,如果用 1 来表示单位宽度的黑色条纹,0 来表示单位宽度的白色条纹,那么条形码可以认为是一个二进制序列,这个二进制序列的长度是 93 位。仔细观察不难发现,在条形码的最左侧、中间和最右侧都有两根稍长的细竖线,分别可以用 101, 01010, 101 来表示。13 位的数字,第一位在最左侧,然后这些竖线将剩余的 12 位分成了两部分 6 位的数码。 […]

Leave a Reply

Your email address will not be published. Required fields are marked *