第22课:随机化调度

阶段四侧信道防护 — 随机化调度通过打乱操作顺序、插入随机延迟和伪操作,使功耗轨迹对齐变得困难,从而削弱 DPA 攻击。

1. DPA 攻击的前提

DPA 的核心步骤是将功耗轨迹对齐——确保相同操作在不同轨迹中出现在相同时间点。随机化调度破坏这个前提。

2. 随机延迟插入

在关键操作前后插入随机数量的空操作(NOP),使操作时间点随机偏移:

✅Verilator验证通过
// random_delay.v - 随机延迟模块
module random_delay #(
    parameter MAX_DELAY = 15,  // 最大延迟周期数
    parameter DELAY_BITS = 4   // 延迟位数
)(
    input  wire                clk,
    input  wire                rst_n,
    input  wire                trigger,     // 触发延迟
    input  wire [DELAY_BITS-1:0] random_val,// 随机延迟值
    output reg                 delay_done   // 延迟完成
);

    reg [DELAY_BITS-1:0] counter;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            counter <= 0;
            delay_done <= 1;
        end else if (trigger) begin
            counter <= random_val[DELAY_BITS-1:0];
            delay_done <= 0;
        end else if (counter > 0) begin
            counter <= counter - 1;
            delay_done <= 0;
        end else begin
            delay_done <= 1;
        end
    end

endmodule

3. 随机操作顺序

AES 的 16 个 S-Box 操作是独立的,可以随机排列执行顺序:

✅Verilator验证通过
// random_scheduler.v - 随机操作调度器
module random_scheduler #(
    parameter NUM_OPS = 16,       // 操作数量
    parameter OP_BITS = 4         // 操作索引位数
)(
    input  wire                      clk,
    input  wire                      rst_n,
    input  wire                      start,
    input  wire [NUM_OPS*4-1:0]      perm_seed,  // 随机排列种子
    output reg  [OP_BITS-1:0]        op_index,   // 当前操作索引
    output reg                       op_valid,   // 操作有效
    output reg                       all_done    // 所有操作完成
);

    // Fisher-Yates 洗牌算法的硬件实现
    reg [OP_BITS-1:0] schedule [0:NUM_OPS-1];
    reg [OP_BITS-1:0] current_idx;
    reg               running;

    integer i;

    initial begin
        for (i = 0; i < NUM_OPS; i = i + 1)
            schedule[i] = i[OP_BITS-1:0];
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            op_index <= 0; op_valid <= 0;
            all_done <= 0; running <= 0;
            current_idx <= 0;
        end else if (start && !running) begin
            // 使用种子生成随机排列
            // 简化实现:使用种子作为初始偏移
            for (i = 0; i < NUM_OPS; i = i + 1)
                schedule[i] <= (i[OP_BITS-1:0] + perm_seed[i*4+:4]) % NUM_OPS;
            current_idx <= 0;
            running <= 1;
            all_done <= 0;
        end else if (running) begin
            if (current_idx < NUM_OPS) begin
                op_index <= schedule[current_idx];
                op_valid <= 1;
                current_idx <= current_idx + 1;
            end else begin
                op_valid <= 0;
                all_done <= 1;
                running <= 0;
            end
        end
    end

endmodule

4. 伪操作注入

在真实操作之间插入随机数量的假操作(使用随机数据),增加功耗噪声:

✅Verilator验证通过
// dummy_ops.v - 伪操作注入模块
module dummy_ops #(
    parameter WIDTH = 128,
    parameter MAX_DUMMY = 3
)(
    input  wire                clk,
    input  wire                rst_n,
    input  wire                real_op_start,    // 真实操作开始
    input  wire [7:0]          random_ctrl,      // 随机控制
    input  wire [WIDTH-1:0]    real_data,        // 真实数据
    output reg                 executing,        // 正在执行
    output reg                 is_real,          // 当前是真实操作
    output reg  [WIDTH-1:0]    active_data       // 当前活跃数据
);

    reg [1:0] dummy_count;
    reg [1:0] dummy_target;
    reg       in_dummy;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            executing <= 0; is_real <= 0;
            active_data <= 0; dummy_count <= 0;
            in_dummy <= 0; dummy_target <= 0;
        end else if (real_op_start) begin
            // 决定插入多少伪操作
            dummy_target <= random_ctrl[7:6];  // 0-3 个
            dummy_count <= 0;
            if (random_ctrl[7:6] > 0) begin
                in_dummy <= 1;
                is_real <= 0;
                active_data <= {random_ctrl, {WIDTH-8{1'b0}}};  // 伪数据
                executing <= 1;
            end else begin
                in_dummy <= 0;
                is_real <= 1;
                active_data <= real_data;
                executing <= 1;
            end
        end else if (executing) begin
            if (in_dummy) begin
                dummy_count <= dummy_count + 1;
                if (dummy_count >= dummy_target - 1) begin
                    in_dummy <= 0;
                    is_real <= 1;
                    active_data <= real_data;
                end else begin
                    active_data <= active_data ^ {random_ctrl, {WIDTH-8{1'b0}}};
                end
            end else begin
                executing <= 0;
            end
        end
    end

endmodule

5. 随机化调度的效果评估

随机化调度的效果取决于随机化程度和攻击者的对齐能力:

DPA 信噪比降低 ≈ 1/√N(N 为随机化范围)

例如,如果 AES 的 16 个 S-Box 操作随机排列,DPA 攻击需要约 16² = 256 倍的轨迹数量才能达到相同效果。

1. 实现随机延迟 AES:在每轮 SubBytes 前插入随机延迟,测量 DPA 攻击的轨迹数量需求变化。

2. 设计一个随机化的 AES 轮函数:16 个 S-Box 以随机顺序执行,每个 S-Box 前后随机延迟。

3. 分析:随机化调度能否单独提供足够的安全保护?还是需要与掩码结合?

4. 实现动态频率调整:在关键操作时随机切换时钟频率。

🏆 成就解锁:混乱大师

你已掌握随机化调度的三大技术:随机延迟、随机操作顺序和伪操作注入,以及它们对 DPA 攻击的削弱效果。

获得徽章:🌪️ CHAOS_MASTER

💡 扩展阅读与参考资源

🔧 实践环境搭建

推荐使用以下工具链进行课程实践:

# 安装 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!");

🔧 Verilator 编译仿真完整流程

# 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 偏重面积和能效,服务器偏重吞吐量。

📚 本课知识图谱

本课涉及的核心概念和技术关系:

💡 调试技巧

Verilog 仿真调试的常用方法:

// 调试示例
initial begin
    $dumpfile("sim.vcd");
    $dumpvars(0, uut);
end

// 断言验证
assert property (@(posedge clk) valid |-> data !== 'x)
    else $error("Invalid data when valid!");

🔧 Verilator 编译仿真完整流程

# 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 偏重面积和能效,服务器偏重吞吐量。