阶段三非对称密码 — 标量乘 k·P 是 ECC 最核心也最耗时的运算。它将点加和点加倍组合,类似于 RSA 的模幂。
标量乘 k·P 是将点 P 自加 k 次。直接方法太慢,使用双-and-add算法:
输入:标量 k,点 P 1. R = O(无穷远点) 2. for i = MSB down to 0: 3. R = 2R(点加倍) 4. if k[i] == 1: R = R + P(点加) 5. return R
这个算法与 RSA 的平方-乘算法结构完全相同!
// ecc_scalar_mul.v - ECC 标量乘模块
module ecc_scalar_mul #(
parameter WIDTH = 256
)(
input wire clk,
input wire rst_n,
input wire start,
input wire [WIDTH-1:0] scalar, // 标量 k
input wire [WIDTH-1:0] px, py, // 基点 P
input wire [WIDTH-1:0] a, // 曲线参数
input wire [WIDTH-1:0] modulus, // 素数 p
output reg [WIDTH-1:0] rx, ry, // 结果 k*P
output reg valid,
output reg busy
);
localparam S_IDLE = 3'd0, S_DBL = 3'd1,
S_ADD = 3'd2, S_NEXT = 3'd3, S_DONE = 3'd4;
reg [2:0] state;
reg [WIDTH-1:0] acc_x, acc_y; // 累积点
reg [WIDTH-1:0] k_reg;
reg [$clog2(WIDTH+1)-1:0] bit_idx;
reg first_point; // 是否第一个点
// 点加/点加倍实例
reg pa_start;
reg pa_dbl;
reg [WIDTH-1:0] pa_px, pa_py, pa_qx, pa_qy;
wire [WIDTH-1:0] pa_rx, pa_ry;
wire pa_valid;
ecc_point_add #(.WIDTH(WIDTH)) u_pa (
.clk(clk), .rst_n(rst_n), .start(pa_start),
.px(pa_px), .py(pa_py),
.qx(pa_qx), .qy(pa_qy),
.a(a), .modulus(modulus), .dbl(pa_dbl),
.rx(pa_rx), .ry(pa_ry), .valid(pa_valid)
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= S_IDLE; rx <= 0; ry <= 0;
valid <= 0; busy <= 0; pa_start <= 0;
acc_x <= 0; acc_y <= 0;
k_reg <= 0; bit_idx <= 0;
first_point <= 1;
end else begin
pa_start <= 0;
case (state)
S_IDLE: begin
if (start) begin
k_reg <= scalar;
bit_idx <= WIDTH - 1; // 从 MSB 开始
first_point <= 1;
busy <= 1;
valid <= 0;
state <= S_DBL;
end
end
S_DBL: begin
if (first_point) begin
// 第一个1位:直接设置 acc = P
if (k_reg[WIDTH-1]) begin
acc_x <= px;
acc_y <= py;
first_point <= 0;
end
k_reg <= k_reg << 1;
bit_idx <= bit_idx - 1;
if (bit_idx == 0)
state <= S_DONE;
else
state <= S_NEXT;
end else begin
// 点加倍: acc = 2*acc
pa_px <= acc_x; pa_py <= acc_y;
pa_dbl <= 1;
pa_start <= 1;
state <= S_ADD;
end
end
S_ADD: begin
if (pa_valid) begin
acc_x <= pa_rx;
acc_y <= pa_ry;
if (k_reg[WIDTH-1]) begin
// 点加: acc = acc + P
pa_px <= pa_rx; pa_py <= pa_ry;
pa_qx <= px; pa_qy <= py;
pa_dbl <= 0;
pa_start <= 1;
state <= S_NEXT;
end else begin
k_reg <= k_reg << 1;
bit_idx <= bit_idx - 1;
if (bit_idx == 0)
state <= S_DONE;
else
state <= S_DBL;
end
end
end
S_NEXT: begin
if (pa_valid) begin
acc_x <= pa_rx;
acc_y <= pa_ry;
k_reg <= k_reg << 1;
bit_idx <= bit_idx - 1;
if (bit_idx == 0)
state <= S_DONE;
else
state <= S_DBL;
end
end
S_DONE: begin
rx <= acc_x;
ry <= acc_y;
valid <= 1;
busy <= 0;
state <= S_IDLE;
end
endcase
end
end
endmodule
双-and-add 算法的关键路径与标量 k 的 Hamming 权重相关——1 位多则多点加操作。这种时间差异泄露了 k 的信息。
无论 k 的位值如何,都执行点加倍和点加:
// 恒定时间双-and-add
for i = MSB down to 0:
Q = 2Q // 总是加倍
T = Q + P // 总是计算 Q+P
if k[i] == 1: Q = T // 条件赋值(不是条件计算!)
else: Q = Q // 保持原值
| 曲线 | p 位数 | 应用 |
|---|---|---|
| secp160r1 | 160 | 受限设备 |
| secp256r1 (P-256) | 256 | TLS, 证书 |
| secp256k1 | 256 | 比特币 |
| secp384r1 (P-384) | 384 | 高安全场景 |
| secp521r1 (P-521) | 521 | 最高安全 |
1. 在 secp256k1 上计算 2G, 3G, 4G,验证结果与标准参考值一致。
2. 实现恒定时间标量乘,确保无论 k 值如何,执行周期数完全相同。
3. 实现窗口法标量乘(wNAF):预处理 2P, 3P, ..., (2ʷ-1)P,减少点加次数。
4. 计算一次 secp256r1 标量乘需要多少次模乘(雅可比坐标)。
你已完成 ECC 标量乘的硬件实现,理解了双-and-add 算法和恒定时间防护。阶段三完成,你已掌握 RSA 和 ECC 两大公钥密码体系!
获得徽章:🏆 ASYMMETRIC_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!");
# 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!");
# 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 偏重面积和能效,服务器偏重吞吐量。