身份证号校验码算法详解权重计算的数学原理引言“身份证号最后一位校验码怎么算”——几乎所有做过中国业务系统的开发者都能背出那组权重7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2也知道加权和 mod 11 再查表。但如果追问一句为什么权重是这串数为什么取模 11 而不是 10为什么余数 2 对应字母 X能答上来的人就少了很多。本文不打算再贴一遍怎么算那是入门内容而是把校验码算法背后隐藏的数学原理一次讲透权重从哪来、模数为什么是素数、校验码表如何推导、这套算法能检测哪些错误、不能检测哪些错误。一、为什么需要校验码1.1 问题背景身份证号是 18 位数字靠人工抄录、输入、传输。任何一位写错都可能把张三变成张王——如果系统无法识别错误错误数据会直接进入数据库成为脏数据。最朴素的防错思路是加一个校验位由前 17 位通过某种规则计算得出第 18 位。校验码的作用是在不需要查库的前提下检测号码是否被写错。1.2 校验码能检测什么以录入错误为例错误类型可分为错误类型举例是否常见单字符替换11010119900101123X→11010119900101126X最常见相邻两位交换...0112...→...0211...常见任意两位交换相距较远的两位数对调较少见增/删一位多打/漏打一位较少见一个好的校验算法应当对高概率错误替换、交换有极高的检测率。这引出了校验算法的数学设计。二、从求和校验到加权校验2.1 朴素校验和为什么不够用最简单的方案是让前 17 位求和模 10 得到校验位使总和能被 10 整除。S d₁ d₂ ... d₁₇ 校验位 (10 - S mod 10) mod 10这个方案有两个致命缺陷位置无关12 34和43 21的校验和一样两位交换检测不出来。模 10 非素数后文会证明模数为合数时存在系统性检测盲区。2.2 加权校验和让每一位位置敏感改进思路给每个位置分配一个权重校验值依赖每一位的数值和它所在的位置S d₁·w₁ d₂·w₂ ... d₁₇·w₁₇数学上错误能检测出来的条件是错误造成的加权和变化量 ≢ 0 (mod m)。对于第 i 位从 a 写成 b的替换错误变化量是(b - a) · wᵢ。要让这个变化量永不为 0需要同时满足(b - a) ≢ 0 (mod m)—— 要求两个不同数字之差不是模数的倍数wᵢ ≢ 0 (mod m)—— 要求权重不能为 0。这就是选择权重和模数的两条硬约束也是下两节数学论证的起点。三、权重系数的来源2 的幂与模 113.1 一个惊人的发现权重表其实就是 2 的幂把2¹, 2², ..., 2¹⁷分别对 11 取模2¹ mod 11 2 2² mod 11 4 2³ mod 11 8 2⁴ mod 11 16 mod 11 5 2⁵ mod 11 32 mod 11 10 2⁶ mod 11 64 mod 11 9 2⁷ mod 11 128 mod 11 7 2⁸ mod 11 256 mod 11 3 2⁹ mod 11 512 mod 11 6 2¹⁰ mod 11 1024 mod 11 1注意到2¹⁰ ≡ 1 (mod 11)这正是费马小定理11 是素数2¹⁰ 2¹¹⁻¹ ≡ 1 mod 11所以2¹¹到2¹⁷只是前面序列的重复2¹¹ ≡ 2¹ (mod 11) 2 2¹² ≡ 2² (mod 11) 4 ...现在把2¹⁷到2¹从右往左排列即校验位左边第 1 位权重取2¹第 2 位取2²……位置从右往左1234567891011121314151617权重 2^k mod 112485109736124851097从左往右读恰好就是大家熟知的权重表位置从左往右: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 权重: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2也就是说身份证校验码的权重系数 校验位右侧第 k 位的权重取2^k mod 11。3.2 为什么序列会回头模 11 下的原根2^1, 2^2, ..., 2^10对 11 取模得到2, 4, 8, 5, 10, 9, 7, 3, 6, 1——注意这 10 个数恰好把 1~10 全部遍历了一遍无一重复。这不是巧合而是因为2 是模 11 的原根primitive root若 g 是模素数 p 的原根则g¹, g², ..., g^(p-1)恰好遍历1 ~ p-1的所有非零剩余类。原根性质带来两个关键收益权重两两不同在 10 位周期内——满足第 2 节的约束wᵢ ≠ 0且不同位置的权重互不相同权重周期性重复周期 10——17 位的权重表只是前 10 个权重循环扩展所以wᵢ wⱼ当且仅当|i - j|是 10 的倍数。3.3 权重表的生成公式综合以上17 位权重可用一个公式概括wᵢ 2^(18 - i) mod 11 i 1, 2, ..., 17从左到右代入验证i1时2¹⁷ mod 11 7i17时2¹ mod 11 2。与标准权重表完全一致。四、为什么取模 11 而不是 10这是整个算法最精妙的设计决策。答案是模数必须是素数且要比数字字母表大。4.1 模 10 的致命缺陷假设模 10权重wᵢ只能取 0~9。由第 2 节的约束替换错误a → b的检测条件为(b - a) · wᵢ ≢ 0 (mod 10)但数字之差b - a取值范围是-9 ~ 9其中包含±5。而模 10 中5 与 10 不互素5 × 2 10 ≡ 0 (mod 10)。于是存在系统性漏洞权重 wᵢ检测不出的替换错误2含因子 2a → a±5差 5 的倍数5×2≡05含因子 5a → a±2, a±4, a±6, a±8偶数差2×5≡00任何替换都检测不出只要权重表里出现 2、5、0对应的位置就有确定性检测盲区——这不是概率问题是必然漏掉。4.2 模 11 为什么完美11 是素数因此任何非零权重与 11 互素wᵢ ≢ 0 (mod 11)时wᵢ有模逆元任何数字差与 11 互素b - a ∈ {±1..±9}绝对值小于 11 且非零不可能被 11 整除。所以对任意替换错误(b - a) · wᵢ ≢ 0 (mod 11) 恒成立结论取模 11素数保证任意位置的任意单字符替换错误 100% 被检测。而 11 是大于 10数字字母表大小的最小素数这保证了模空间足够容纳全部校验结果。4.3 为什么不取更大的素数取 17、19 也可以但会产生更多校验码取值如余数 10 以上需要新符号破坏18 位纯数字/单字符的简洁性。11 是在保证检测能力和保持可读性之间的最优平衡。五、校验码的生成与验证5.1 校验码表不是查出来的是算出来的很多人记校验码表[1, 0, X, 9, 8, 7, 6, 5, 4, 3, 2]但这份表其实来自一个公式。设r S mod 11S 为前 17 位加权和标准规定校验码数值c满足(S c) mod 11 1即c ≡ (1 - r) mod 11 ≡ (12 - r) mod 11。逐个代入余数 rc (12 - r) mod 11校验码字符012 mod 11 11111 mod 11 00210X3994885776667558449331022表格第三列[1, 0, X, 9, 8, 7, 6, 5, 4, 3, 2]——与标准校验码表逐位吻合。当c 10时用罗马数字X表示10 是一个字符能表达的最大值保持 18 位不变。5.2 为什么是同余 1而不是同余 0这是 ISO 7064 系列算法的统一设计使用一个非零常数这里取 1。若规定完整号码加权和 ≡ 0那么全零字符串000000000000000000的加权和恒为 0天然满足校验——一个全是 0 的号码会被当成合法身份证号。而规定同余 1 之后全零字符串被自然排除。这也让验证变得非常优雅不需要反查校验位直接对完整 18 位校验位权重隐含为 1做一次加权求和检查是否同余于 1 即可。5.3 完整示例 1校验码是数字身份证11010119900101123X前 17 位为11010119900101123位值: 1 1 0 1 0 1 1 9 9 0 0 1 0 1 1 2 3 权重: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2S 1×7 1×9 0×10 1×5 0×8 1×4 1×2 9×1 9×6 0×3 0×7 1×9 0×10 1×5 1×8 2×4 3×2 126 r 126 mod 11 5 校验码 (12 - 5) mod 11 7完整号码110101199001011237✅5.4 完整示例 2校验码是 X身份证11010519491231002X前 17 位为11010519491231002位值: 1 1 0 1 0 5 1 9 4 9 1 2 3 1 0 0 2 权重: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2S 1×7 1×9 0×10 1×5 0×8 5×4 1×2 9×1 4×6 9×3 1×7 2×9 3×10 1×5 0×8 0×4 2×2 167 r 167 mod 11 2 校验码 (12 - 2) mod 11 10 → X完整号码11010519491231002X✅X 必须大写5.5 验证的等价形式生成时校验位满足(S c) ≡ 1 (mod 11)因此验证时只需一步(前17位加权和 校验位数值) mod 11 1 ⟺ 校验通过这与源码ChineseIdCardValidator的实现一致计算前 17 位加权和mod 11得余数用余数查校验码表比对最后一位。六、纠错能力分析这套算法到底有多强6.1 数学框架错误检测的本质是判断加权和变化量是否 ≡ 0 (mod 11)。基于前文的原根性质可以精确推导各类错误的检测率错误类型检测条件检测率说明单字符替换(b-a)·wᵢ ≢ 0100%b-a与wᵢ均与 11 互素乘积恒非零相邻两位交换(a-b)·(wᵢ-wᵢ₊₁) ≢ 0100%相邻权重各不相同任意两位交换(a-b)·(wᵢ-wⱼ) ≢ 0≈94.9%仅当wᵢ wⱼ间隔 10 位时失效隔 10 位交换(a-b)·(wᵢ-wⱼ) 00%权重周期 10wᵢ wⱼ加权和不变任意交换的失效率17 位两两组合共C(17,2) 136对其中间隔 10 位的7对如第 1 位与第 11 位权重相同。检测率129/136 ≈ 94.9%。6.2 与朴素校验和的对比对比项朴素校验和mod 10ValidX 校验码mod 11权重全部为 12^k mod 11位置敏感单字符替换100%碰巧可行100%数学保证相邻交换0%检测不出100%任意交换0%≈ 94.9%全零串误判合法非法同余 1 设计权重含 0/不互素因子有模 10 缺陷无位置敏感 素数模让检测能力发生质变——这就是全部数学设计的价值所在。七、同源算法ISO 7064 家族身份证校验码采用的是ISO 7064:1983 MOD 11-2标准。这套加权和 素数模 非零常数的思想被广泛应用于全球各类编号系统算法模数基数典型应用MOD 11-2112 的幂中国身份证、ISBN-10 书号MOD 37-2372 的幂通用字母数字串MOD 97-109710IBAN 国际银行账号MOD 11-3113 的幂部分证件号码GB 32100-201531特定权重统一社会信用代码它们共享同一套数学骨架权重用基数 k 的幂次对素数模取模原根性保证权重两两不同校验位使完整串满足一个非零同余常数。有趣的是统一社会信用代码18 位与身份证18 位虽然长度相同但分别采用模 31 与模 11 两套权重体系——这是 ValidX 同时提供ChineseIdCard与UnifiedSocialCreditCode两个独立注解的原因。八、ValidX 中的实现8.1 注解方式publicclassUserDTO{NotBlank(message身份证号不能为空)ChineseIdCardprivateStringidCard;}ChineseIdCard内部自动完成格式验证 → 省份码验证 → 出生日期验证含闰年→校验码验证校验逻辑与本文推导的算法完全一致。8.2 链式 APIValidXvalidatorValidX.init().field(身份证号).isChineseIdCard(idCard);if(!validator.passed()){thrownewBusinessException(validator.getErrors());}8.3 源码对照核心常量与本文推导一一对应// 权重系数 2^(18-i) mod 11publicstaticfinalInteger[]idCardWeight{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};// 校验码表r S mod 11 时的校验字符publicstaticfinalString[]idCardCheck{1,0,X,9,8,7,6,5,4,3,2};// 验证加权和 mod 11按余数查表比对最后一位intlastResultresultSum%11;returnidCardMap.get(lastResult).equals(lastStr);15 位旧版身份证在校验时会被自动升位为 18 位年份前补19后再计算校验码。九、常见问题Q1为什么校验码会有 X余数r 2时校验码数值为 10。两位数会破坏18 位的定长结构因此借用罗马数字X表示 10单字符表达。X 只能出现在末位且必须大写。Q2权重表需要背吗为什么网上有不同写法不需要背。如果看到其他文章写的是2, 4, 8, 5, 10, 9, 7, 3, 6, 1, ...那是从右往左排列标准权重表7, 9, 10, ...是从左往右排列。两者只是方向不同计算时必须统一方向。Q3校验码能防伪造吗不能。校验码的作用是防错检测录入/传输错误不是防伪。算法和权重公开任何人都能算出合法校验码。真正的防伪依赖公安系统对号码的实名核验。这也提醒我们校验码通过 ≠ 身份真实。Q4全 0 的号码能通过校验吗不能。这正是同余于 1而非同余于 0的设计目的——全 0 串加权和为 0不满足同余 1被直接排除。Q5校验码算法能检测出改生日的篡改吗可以。改动出生日期任意一位都会改变加权和mod 11后与校验位不匹配检测率 100%单字符替换场景。Q615 位身份证怎么校验15 位老身份证没有校验码算法上先补19升为 17 位再计算并补上第 18 位校验码然后按 18 位规则验证。ValidX 自动处理这一转换。十、总结用一张图回顾整条数学推导链原根性质2 是模 11 的原根 │ 2^1..2^17 mod 11 遍历 1..10周期 10 ▼ 权重表 wᵢ 2^(18-i) mod 11 [7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2] │ 素数模 11任意非零权重 × 任意非零数字差 ≢ 0 ▼ 加权和 S Σ dᵢ·wᵢ 位置敏感 │ ▼ 校验位 c (12 - r) mod 11r S mod 11 完整串同余于 1 │ ▼ 校验码表 [1, 0, X, 9, 8, 7, 6, 5, 4, 3, 2] 10 → X核心要点就三句话权重来自 2 的幂对 11 取模——原根性保证了位置敏感 权重两两不同模数取素数 11——数学上保证了任何单字符错误 100% 可检测校验码让完整号码同余于 1——验证一步完成且天然排除全零串。理解了这三点你不仅记住了权重表更掌握了它为什么是这样。以后再遇到任何 ISO 7064 家族的校验算法IBAN、统一社会信用代码都能一眼看穿其数学本质。