阶段二哈希与认证 — CRC(循环冗余校验)虽然不是密码学安全哈希,但在密码学硬件中广泛用于错误检测。LFSR 结构使其硬件实现极其高效。
CRC 基于多项式除法:将消息视为 GF(2) 上的多项式,除以生成多项式,余数即为 CRC 值。
其中 n 是 CRC 位数,g(x) 是生成多项式。
| 名称 | 多项式(十六进制) | 应用 |
|---|---|---|
| CRC-8 | 0x07 | SMBus |
| CRC-16-CCITT | 0x1021 | X.25, Bluetooth |
| CRC-32 | 0x04C11DB7 | Ethernet, ZIP |
| CRC-32C | 0x1EDC6F41 | iSCSI, SCTP |
线性反馈移位寄存器(LFSR)是 CRC 硬件实现的标准结构。每一位数据输入触发一次移位和条件异或。
// crc32.v - CRC-32 硬件实现(LFSR 结构)
module crc32 (
input wire clk,
input wire rst_n,
input wire clear, // 清除 CRC 寄存器
input wire data_valid, // 数据有效
input wire [7:0] data_in, // 8位数据输入
output reg [31:0] crc_out // CRC-32 输出
);
// CRC-32 生成多项式: 0x04C11DB7
// 反射多项式: 0xEDB88320 (用于逐位处理)
reg [31:0] crc_reg;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
crc_reg <= 32'hFFFFFFFF; // CRC 初始化为全1
end else if (clear) begin
crc_reg <= 32'hFFFFFFFF;
end else if (data_valid) begin
// 逐字节处理(8位并行)
// 使用反射多项式,LSB 优先
crc_reg[0] <= crc_reg[24] ^ crc_reg[30] ^ data_in[0] ^ data_in[6];
crc_reg[1] <= crc_reg[25] ^ crc_reg[31] ^ data_in[1] ^ data_in[7] ^
crc_reg[24] ^ crc_reg[30] ^ data_in[0] ^ data_in[6];
crc_reg[2] <= crc_reg[26] ^ data_in[2] ^
crc_reg[24] ^ crc_reg[30] ^ data_in[0] ^ data_in[6];
crc_reg[3] <= crc_reg[27] ^ data_in[3] ^
crc_reg[25] ^ crc_reg[31] ^ data_in[1] ^ data_in[7];
crc_reg[4] <= crc_reg[28] ^ data_in[4] ^
crc_reg[26] ^ data_in[2] ^
crc_reg[24] ^ crc_reg[30] ^ data_in[0] ^ data_in[6];
crc_reg[5] <= crc_reg[29] ^ data_in[5] ^
crc_reg[27] ^ data_in[3] ^
crc_reg[25] ^ crc_reg[31] ^ data_in[1] ^ data_in[7];
crc_reg[6] <= crc_reg[30] ^ data_in[6] ^
crc_reg[28] ^ data_in[4] ^
crc_reg[26] ^ data_in[2];
crc_reg[7] <= crc_reg[31] ^ data_in[7] ^
crc_reg[29] ^ data_in[5] ^
crc_reg[27] ^ data_in[3];
crc_reg[8] <= crc_reg[0] ^ crc_reg[28] ^ data_in[4];
crc_reg[9] <= crc_reg[1] ^ crc_reg[29] ^ data_in[5];
crc_reg[10] <= crc_reg[2] ^ crc_reg[30] ^ data_in[6];
crc_reg[11] <= crc_reg[3] ^ crc_reg[31] ^ data_in[7];
crc_reg[12] <= crc_reg[4] ^ crc_reg[24] ^ data_in[0];
crc_reg[13] <= crc_reg[5] ^ crc_reg[25] ^ data_in[1];
crc_reg[14] <= crc_reg[6] ^ crc_reg[26] ^ data_in[2];
crc_reg[15] <= crc_reg[7] ^ crc_reg[27] ^ data_in[3];
crc_reg[16] <= crc_reg[8] ^ crc_reg[24] ^ data_in[0] ^
crc_reg[28] ^ data_in[4];
crc_reg[17] <= crc_reg[9] ^ crc_reg[25] ^ data_in[1] ^
crc_reg[29] ^ data_in[5];
crc_reg[18] <= crc_reg[10] ^ crc_reg[26] ^ data_in[2] ^
crc_reg[30] ^ data_in[6];
crc_reg[19] <= crc_reg[11] ^ crc_reg[27] ^ data_in[3] ^
crc_reg[31] ^ data_in[7];
crc_reg[20] <= crc_reg[12] ^ crc_reg[28] ^ data_in[4];
crc_reg[21] <= crc_reg[13] ^ crc_reg[29] ^ data_in[5];
crc_reg[22] <= crc_reg[14] ^ crc_reg[24] ^ data_in[0];
crc_reg[23] <= crc_reg[15] ^ crc_reg[25] ^ data_in[1] ^
crc_reg[30] ^ data_in[6];
crc_reg[24] <= crc_reg[16] ^ crc_reg[26] ^ data_in[2] ^
crc_reg[31] ^ data_in[7];
crc_reg[25] <= crc_reg[17] ^ crc_reg[27] ^ data_in[3];
crc_reg[26] <= crc_reg[18] ^ crc_reg[28] ^ data_in[4] ^
crc_reg[24] ^ data_in[0];
crc_reg[27] <= crc_reg[19] ^ crc_reg[29] ^ data_in[5] ^
crc_reg[25] ^ data_in[1];
crc_reg[28] <= crc_reg[20] ^ crc_reg[30] ^ data_in[6] ^
crc_reg[26] ^ data_in[2];
crc_reg[29] <= crc_reg[21] ^ crc_reg[31] ^ data_in[7] ^
crc_reg[27] ^ data_in[3];
crc_reg[30] <= crc_reg[22] ^ crc_reg[28] ^ data_in[4];
crc_reg[31] <= crc_reg[23] ^ crc_reg[29] ^ data_in[5];
end
end
// CRC-32 最终输出需要取反
assign crc_out = ~crc_reg;
endmodule
更优雅的实现方式是使用参数化设计:
// crc_generic.v - 参数化 CRC 模块
module crc_generic #(
parameter WIDTH = 32, // CRC 宽度
parameter [WIDTH-1:0] POLY = 32'h04C11DB7, // 生成多项式
parameter [WIDTH-1:0] INIT = 32'hFFFFFFFF, // 初始值
parameter REFLECT_INPUT = 1, // 输入反射
parameter REFLECT_OUTPUT = 1, // 输出反射
parameter XOR_OUTPUT = 32'hFFFFFFFF // 输出异或值
)(
input wire clk,
input wire rst_n,
input wire clear,
input wire data_valid,
input wire [7:0] data_in,
output wire [WIDTH-1:0] crc_out
);
reg [WIDTH-1:0] crc_reg;
// 逐位处理(通用但较慢)
integer i;
reg [7:0] din_reflected;
reg [WIDTH-1:0] next_crc;
// 输入反射
always @(*) begin
din_reflected[0] = data_in[7];
din_reflected[1] = data_in[6];
din_reflected[2] = data_in[5];
din_reflected[3] = data_in[4];
din_reflected[4] = data_in[3];
din_reflected[5] = data_in[2];
din_reflected[6] = data_in[1];
din_reflected[7] = data_in[0];
end
always @(*) begin
next_crc = crc_reg;
for (i = 0; i < 8; i = i + 1) begin
if (next_crc[0] ^ (REFLECT_INPUT ? din_reflected[i] : data_in[i]))
next_crc = (next_crc >> 1) ^ POLY;
else
next_crc = next_crc >> 1;
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
crc_reg <= INIT;
else if (clear)
crc_reg <= INIT;
else if (data_valid)
crc_reg <= next_crc;
end
assign crc_out = crc_reg ^ XOR_OUTPUT;
endmodule
1. 验证 CRC-32("123456789") = 0xCBF43926(标准测试向量)。
2. 实现一个 CRC-16-CCITT 模块,用于蓝牙数据包校验。
3. 设计一个 CRC 校验器:同时计算 CRC 并与附加的 CRC 值比较,输出 pass/fail。
4. 分析 CRC-32 的碰撞概率:对于 n 位消息,两个不同消息具有相同 CRC 的概率是多少?
你已掌握 CRC 的数学原理、LFSR 硬件实现和参数化设计。CRC 是数字通信和存储系统中不可或缺的错误检测组件!
获得徽章:🔍 CRC_CRAFTSMAN
推荐使用以下工具链进行课程实践:
# 安装 Verilator
sudo apt install verilator
# 安装 Icarus Verilog(可选)
sudo apt install iverilog
# 安装 GTKWave(波形查看器)
sudo apt install gtkwave
# 验证安装
verilator --lint-only --version
iverilog -V
密码学硬件实现的关键性能指标:
这些指标之间通常存在 trade-off,设计时需根据应用场景权衡。
本课涉及的核心概念和技术关系:
Verilog 仿真调试的常用方法:
// 调试示例
initial begin
$dumpfile("sim.vcd");
$dumpvars(0, uut);
end
// 断言验证
assert property (@(posedge clk) valid |-> data !== 'x)
else $error("Invalid data when valid!");
# 1. 语法检查
verilator --lint-only module.v
# 2. 创建 C++ 测试主函数
cat > sim_main.cpp << 'EOF'
#include "Vmodule.h"
#include "verilated.h"
int main(int argc, char** argv) {
Verilated::commandArgs(argc, argv);
Vmodule* top = new Vmodule;
top->clk = 0; top->rst_n = 0;
top->eval();
top->rst_n = 1;
for (int i = 0; i < 100; i++) {
top->clk = !top->clk;
top->eval();
}
delete top;
return 0;
}
EOF
# 3. 编译
verilator -cc module.v --exe sim_main.cpp
make -C obj_dir -f Vmodule.mk
# 4. 运行
./obj_dir/Vmodule
密码硬件的性能评估维度:
| 指标 | 单位 | 说明 |
|---|---|---|
| 面积 | GE / LUT | 等效门数或查找表数量 |
| 频率 | MHz | 最大时钟频率 |
| 吞吐量 | Gbps | 每秒处理的数据量 |
| 延迟 | 周期数 | 从输入到输出的周期 |
| 能效 | pJ/bit | 每比特能耗 |
| 面积效率 | Gbps/GE | 单位面积吞吐量 |
不同应用场景对指标优先级不同:IoT 偏重面积和能效,服务器偏重吞吐量。