反馈

CRC 校验原理:多项式除法和 CRC16/32 怎么算

CRC(Cyclic Redundancy Check,循环冗余校验)几乎存在于每一次数据传输和存储背后:以太网帧、USB 传输、ZIP/PNG 文件格式、Modbus 工业协议……它要解决的问题很朴素:数据在传输或存储过程中有没有出错


目录

  1. CRC 是什么,解决什么问题
  2. 多项式除法:核心原理
  3. CRC16 vs CRC32
  4. CRC 和哈希算法的区别
  5. 实际应用场景
  6. 代码示例

1. CRC 是什么,解决什么问题

数据在传输(网线、无线信号)或存储(硬盘、闪存)过程中,可能因为噪声、干扰、硬件故障产生位翻转(0 变 1 或 1 变 0)。CRC 的作用是:发送方按数据算出一个"校验值"附在末尾,接收方收到后重新计算一次,两次结果不一致就说明数据在路上出错了,需要重传或报错。

它不负责纠错(不知道错在哪一位),只负责检测——这也是为什么叫"校验"而不是"纠错"。

2. 多项式除法:核心原理

CRC 的数学基础是二进制多项式除法。可以类比成小学学的"除法验证":把数据看成一个大二进制数,除以一个固定的"生成多项式",余数就是 CRC 值。

用一个简化的例子理解(真实 CRC 用异或代替减法,但逻辑相通):

数据:110101
生成多项式(简化为4位):1011

用异或做"除法":
110101
1011
----
010001
 1011
 ----
 001101
  1011
  ----
  00110  ← 这就是余数(简化版 CRC 值)

真实的 CRC16/32 用的生成多项式经过精心挑选(比如 CRC-32 用 0x04C11DB7),能保证"绝大多数常见的位错误模式"都会导致余数变化,从而被检测出来。

3. CRC16 vs CRC32

CRC16 CRC32
校验位长度 16 位 32 位
检测能力 较弱,适合短数据 更强,能检测更长数据里的错误
典型场景 Modbus 工业协议、老式通信协议 ZIP/PNG/以太网帧、git 对象校验
计算开销 略低 略高,但现代硬件差异可忽略

简单说:数据量小、协议历史悠久用 CRC16;现代通用场景基本都用 CRC32。两者不能互相验证,必须用同一种算法。

4. CRC 和哈希算法的区别

CRC 常被拿来和 MD5/SHA 这类哈希算法比较,但它们的设计目的完全不同:

CRC MD5/SHA 等密码学哈希
设计目的 检测随机的传输/存储错误 抵抗故意的恶意篡改
抗碰撞设计 没有,故意构造两个 CRC 相同的数据非常容易 设计上要求极难构造碰撞
计算速度 非常快,常有硬件指令加速(如 CRC32C) 较慢
能不能用于安全场景 不能,几毫秒就能伪造 MD5/SHA1 已不安全,SHA-256 等仍安全

一句话:CRC 防的是"意外出错",哈希算法(用对的话)防的是"有人故意搞破坏"。如果场景涉及安全性(比如校验一个文件是否被恶意篡改),必须用密码学哈希,CRC 完全不够用。

5. 实际应用场景

  • ZIP 文件:每个压缩条目都带 CRC-32,解压时校验数据完整性
  • PNG 图片:每个数据块(chunk)末尾带 CRC-32
  • 以太网帧:每个网络帧末尾带 CRC-32(FCS 字段),硬件层面自动校验,出错的帧直接丢弃
  • Modbus/工业协议:普遍用 CRC16 校验报文
  • git:对象存储用 CRC 做打包文件(pack file)的完整性校验(内容寻址本身用 SHA-1/256)

6. 代码示例

// Node.js 内置 zlib 提供 CRC32
const zlib = require('zlib');
const buf = Buffer.from('hello world');
console.log(zlib.crc32(buf).toString(16));

在线 CRC 校验工具:CRC-32校验 · CRC-16校验