2252 lines
118 KiB
Verilog
2252 lines
118 KiB
Verilog
// mlkem_top.v - ML-KEM 密钥生成顶层集成。通过 k_i 运行时选择参数集:
|
||
// k=2 (ML-KEM-512, eta1=3), k=3 (768), k=4 (1024)。
|
||
// 存储器按 KMAX(最坏情况 = ML-KEM-1024)大小设计;k_i 在 start_i 时
|
||
// 选择有效子范围。
|
||
//
|
||
// 流式 valid/ready 接口。给定种子 d 和 z,根据 FIPS 203 算法 16
|
||
// (KeyGen_internal) 计算 ML-KEM 密钥对:
|
||
// (rho,sigma) = G(d || K)
|
||
// A_hat[i][j] = SampleNTT(rho || j || i) i,j 在 0..K-1 范围内
|
||
// s[i] = CBD3(PRF(sigma, i)), e[i] = CBD3(PRF(sigma, K+i))
|
||
// s_hat[i] = NTT(s[i]); e_hat[i] = NTT(e[i])
|
||
// t_hat[i] = e_hat[i] + sum_j A_hat[i][j] o s_hat[j]
|
||
// ek = byteEncode12(t_hat[0..K-1]) || rho
|
||
// dk = byteEncode12(s_hat[0..K-1]) || ek || H(ek) || z
|
||
//
|
||
// 按阶段增量构建,并针对参考黄金向量
|
||
// (test_framework/modules/mlkem_keygen/golden) 和 NIST KAT 进行逐阶段验证。
|
||
//
|
||
// 使用独立(已验证)的叶子模块,共享同一个 keccak_core:
|
||
// sha3_top_shared, sample_ntt_sync_shared, sample_cbd_sync_shared, ntt_core,
|
||
// poly_mul_sync, comp_decomp_sync。
|
||
|
||
`include "defines.vh"
|
||
|
||
(* use_dsp = "no" *)
|
||
module mlkem_top #(
|
||
parameter KMAX = 4 // 存储器大小(最坏情况 = ML-KEM-1024)
|
||
) (
|
||
input clk,
|
||
input rst_n,
|
||
input [2:0] k_i, // 运行时 ML-KEM 参数:2=512, 3=768, 4=1024
|
||
input [1:0] op_i, // 0=密钥生成, 1=封装, 2=解封装(在 start_i 时捕获)
|
||
input [255:0] d_i, // 密钥生成种子 d(字节 0 在 d_i[7:0] 中)
|
||
input [255:0] z_i, // 隐式拒绝种子 z
|
||
input [255:0] msg_i, // 封装消息 m(字节 0 在 msg_i[7:0] 中)
|
||
input start_i, // 开始密钥生成的脉冲
|
||
output busy_o, // 运行时为高电平
|
||
output done_o, // ek/dk 就绪时输出脉冲
|
||
|
||
// Encaps ek 输入:在 start_i 之前以 op_i=1 将 ek 字节流式写入 ek_bram。
|
||
// ek_in_we 将字节 ek_in_byte 写入地址 ek_in_addr。
|
||
input ek_in_we, // 写入一个 ek 字节(仅在 ST_IDLE 中 Encaps 预加载时有效)
|
||
input [10:0] ek_in_addr, // ek 字节地址 0..ek_bytes-1
|
||
input [7:0] ek_in_byte, // ek 字节值
|
||
// Decaps dk 输入:在 start_i 之前以 op_i=2 将 dk 字节(=sk, 768K+96)
|
||
// 流式写入设计。加载逻辑按区域路由每个字节:
|
||
// [0,384K) -> dk_pke (dkp_bram) = s_hat 编码
|
||
// [384K, 768K+32) -> ek_pke (ek_bram) = t_hat 编码 || rho
|
||
// [768K+32, 768K+64) -> H(ek) (hek_r)
|
||
// [768K+64, 768K+96) -> z (z_r)
|
||
input dk_in_we, // 写入一个 dk 字节(ST_IDLE Decaps 预加载)
|
||
input [11:0] dk_in_addr, // dk 字节地址 0..(768K+96)-1
|
||
input [7:0] dk_in_byte, // dk 字节值
|
||
// Decaps 密文输入:在 start_i 之前将 c 字节(=ct)流式写入 c_in_bram。
|
||
// 与 ct_bram 分开保存,这样计算出的 c' 可以与原始 c 比较
|
||
// (且 J(z||c) 可以读取 c)而不会产生别名。
|
||
input c_in_we, // 写入一个 c 字节(ST_IDLE Decaps 预加载)
|
||
input [10:0] c_in_addr, // c 字节地址 0..ct_bytes-1
|
||
input [7:0] c_in_byte, // c 字节值
|
||
// Encaps 共享密钥输出(= K),在 done_o 时有效
|
||
output [255:0] ss_o,
|
||
// Encaps 密文回读抽头:按索引 0..ct_bytes-1 输出 ct 字节
|
||
input [10:0] dbg_ct_idx_i,
|
||
output [7:0] dbg_ct_o,
|
||
|
||
// Debug 回读抽头:按(多项式槽位,索引)读取一个存储系数。
|
||
// 允许各阶段测试平台验证中间结果,无需宽总线。
|
||
input [5:0] dbg_slot_i, // 多项式槽位(见下面的 localparam)
|
||
input [7:0] dbg_idx_i, // 系数索引 0..255
|
||
output [11:0] dbg_coeff_o,
|
||
// Debug 字节回读:ek (sel=0, 0..799) / dk_pke (sel=1, 0..767)
|
||
input dbg_byte_sel_i,
|
||
input [10:0] dbg_byte_idx_i,
|
||
output [7:0] dbg_byte_o,
|
||
// Debug 完整 dk 回读:dk = dk_pke(768) || ek(800) || H(ek)(32) || z(32)
|
||
// = 1632 字节。索引 0..1631。
|
||
input [11:0] dbg_dk_idx_i,
|
||
output [7:0] dbg_dk_o,
|
||
// Debug 哈希输出抽头
|
||
output [255:0] dbg_rho_o,
|
||
output [255:0] dbg_sigma_o,
|
||
// Encaps debug 抽头:r(G 高半部分)和 H(ek)
|
||
output [255:0] dbg_r_o,
|
||
output [255:0] dbg_hek_o,
|
||
// Decaps debug 抽头:m'(解密输出)、K-bar(J 输出)、解析后的 z/h。
|
||
output [255:0] dbg_mprime_o,
|
||
output [255:0] dbg_kbar_o,
|
||
output [255:0] dbg_decz_o, // 解析后的 z(dk[768K+64:+32])
|
||
output [255:0] dbg_dech_o // 解析后的 H(ek)(dk[768K+32:+32])
|
||
);
|
||
|
||
localparam Q = `Q; // 3329
|
||
|
||
// 运行时 ML-KEM 参数,在 start_i 时捕获。
|
||
reg [2:0] k_r;
|
||
// FIPS 203:ML-KEM-512 (k=2) 时 eta1 = 3,k=3/4 时 eta1 = 2。
|
||
wire [1:0] eta1_rt = (k_r == 3'd2) ? 2'd3 : 2'd2;
|
||
|
||
// 运行时推导的大小(k_r 取值为 {2,3,4})。小乘法成本低廉。
|
||
wire [5:0] kk_rt = k_r * k_r; // 4/9/16
|
||
wire [5:0] slot_s_rt = kk_rt; // s_hat 基槽位
|
||
wire [5:0] slot_e_rt = kk_rt + k_r; // e_hat 基槽位
|
||
wire [5:0] slot_t_rt = kk_rt + {1'b0, k_r} + {1'b0, k_r}; // t_hat 基槽位 = kk+2k
|
||
wire [11:0] ek_bytes_rt = 12'd384 * {9'b0, k_r} + 12'd32; // 800/1184/1568
|
||
wire [11:0] dk_bytes_rt = 12'd384 * {9'b0, k_r}; // 768/1152/1536
|
||
// 完整 dk = dk_pke(dk_bytes) || ek(ek_bytes) || H(ek)(32) || z(32)。区域
|
||
// 边界(用于 Decaps dk 加载路由和 dk 回读)。
|
||
wire [11:0] dk_ek_end = dk_bytes_rt + ek_bytes_rt; // ek_pke 区域结束
|
||
wire [11:0] dk_hek_end = dk_ek_end + 12'd32; // H(ek) 区域结束
|
||
// 加载时边界:dk 在 start_i 之前流式输入,因此 k_r 尚未
|
||
// 捕获。使用实时 k_i 输入而非 k_r 来路由 dk 加载。
|
||
wire [11:0] dkp_bytes_ld = 12'd384 * {9'b0, k_i}; // 768/1152/1536
|
||
wire [11:0] ek_bytes_ld = 12'd384 * {9'b0, k_i} + 12'd32; // 800/1184/1568
|
||
wire [11:0] dk_ek_end_ld = dkp_bytes_ld + ek_bytes_ld; // ek_pke 区域结束
|
||
wire [11:0] dk_hek_end_ld= dk_ek_end_ld + 12'd32; // H(ek) 区域结束
|
||
// H(ek) 块数 = ceil((ek_bytes+1)/136):k=2/3/4 时分别为 6/9/12
|
||
wire [3:0] h_nblk_rt = (k_r == 3'd2) ? 4'd6 : (k_r == 3'd3) ? 4'd9 : 4'd12;
|
||
wire [11:0] h_last_rt = {6'b0, h_nblk_rt} * 12'd136 - 12'd1; // 最终填充字节索引
|
||
|
||
// ---- Encaps 运行时参数 ----
|
||
reg [1:0] op_r; // 0=密钥生成 1=封装 2=解封装(在 start 时捕获)
|
||
reg [255:0] m_r; // Encaps 消息 m(在 start 时捕获);Decaps 重用为 m'
|
||
reg [255:0] ss_r; // Encaps 共享密钥 K(= G 输出低半部分)
|
||
reg [255:0] r_r; // Encaps PRF 种子 r(= G 输出高半部分)
|
||
// ---- Decaps 运行时参数(加载时从 dk 解析)----
|
||
reg [255:0] z_r; // 隐式拒绝种子 z(dk 尾部),加载时捕获
|
||
reg [255:0] kbar_r; // K-bar = J(z||c)(D5)
|
||
// FIPS 203:所有参数集 eta2 = 2。
|
||
wire [1:0] eta2_rt = 2'd2;
|
||
// 压缩参数:(du,dv) 在 k=2/3 时为 (10,4),k=4 时为 (11,5)。
|
||
wire [4:0] du_rt = (k_r == 3'd4) ? 5'd11 : 5'd10;
|
||
wire [4:0] dv_rt = (k_r == 3'd4) ? 5'd5 : 5'd4;
|
||
// 密文字节大小:c1 = 32*du*k, c2 = 32*dv, ct = c1+c2。
|
||
wire [11:0] c1_bytes_rt = 12'd32 * {7'b0, du_rt} * {9'b0, k_r}; // 640/960/1408
|
||
wire [11:0] c2_bytes_rt = 12'd32 * {7'b0, dv_rt}; // 128/128/160
|
||
wire [11:0] ct_bytes_rt = c1_bytes_rt + c2_bytes_rt; // 768/1088/1568
|
||
// 共享密钥输出:Encaps 直接驱动 ss_r = K。Decaps 隐式拒绝:
|
||
// ss = (c' == c) ? K' : K-bar。K' 在 ss_r 中,K-bar 在 kbar_r 中;
|
||
// dec_reject 是来自 D7 锁存的 c' != c 标志(密钥生成/封装时为 0,
|
||
// 因此 ss_r 直接通过)。
|
||
assign ss_o = dec_reject ? kbar_r : ss_r;
|
||
|
||
// ---- E1: rho 加载 + byteDecode12 簿记 ----
|
||
// rho 加载:从 ek_bram 中偏移 384*k 处读取 32 个字节到 rho_r。
|
||
reg [5:0] rl_idx; // 0..33 rho 字节的预读指针
|
||
reg [5:0] rl_widx; // 0..31 正在写入的字节(比 rl_idx 延迟 1 周期)
|
||
reg rl_vld; // 本周起有字节到达
|
||
wire [11:0] rl_ek_off = dk_bytes_rt + {6'b0, rl_idx}; // ek 地址 = 384k + idx
|
||
// byteDecode12:读取 3 个 ek 字节转换为 2 个系数写入 bank_t。
|
||
// 遍历 K 个多项式 * 128 个三元组。每个三元组 5 周期微相:
|
||
// ph0..2 取回 b0,b1,b2(预读,1 周期 bram 延迟),
|
||
// ph3 写入 c0, ph4 写入 c1。
|
||
reg [2:0] td_poly; // 0..k-1 t_hat 多项式索引
|
||
reg [7:0] td_trip; // 0..127 多项式内三元组
|
||
reg [2:0] td_ph; // 0..4 微相
|
||
reg [7:0] td_b0, td_b1, td_b2; // 捕获的 ek 字节
|
||
reg td_done;
|
||
// 三元组的 ek 字节地址:poly*384 + trip*3 + (ph 当 ph<3)
|
||
wire [11:0] td_base = {td_poly, 7'd0} * 12'd3; // poly*384 (=poly*256*1.5) 见下文
|
||
// poly*384 + trip*3 + byteidx; byteidx = ph (0,1,2) 在取回阶段
|
||
wire [11:0] td_byteidx = {2'd0, td_trip, 1'b0} + {3'd0, td_trip}; // trip*3
|
||
wire [11:0] td_ekaddr = ({4'd0,td_poly}*12'd384) + td_byteidx + {9'd0, td_ph};
|
||
// 解码后的系数:c0 = b0 | ((b1&0xF)<<8); c1 = (b1>>4) | (b2<<4)
|
||
wire [11:0] td_c0 = {td_b1[3:0], td_b0};
|
||
wire [11:0] td_c1 = {td_b2, td_b1[7:4]};
|
||
// TDEC 字节源:Encaps 读取 ek (ek_rd_data);Decaps D2 (ST_DEC_SDEC)
|
||
// 重用同一机器对 dk_pke 进行 byteDecode12 得到 s_hat,读取 dkp_bram。
|
||
wire td_dec_s = (st == ST_DEC_SDEC);
|
||
wire [7:0] td_byte = td_dec_s ? dkp_rd_data : ek_rd_data;
|
||
// TDEC 的 bank_a 写入(已寄存);t_hat[td_poly] -> bank_a 槽位
|
||
// td_poly*K。td_wa 是 bank_a 字节地址 (PA_AW=12)。
|
||
reg td_we;
|
||
reg [11:0] td_wa; // bank_a 地址 (PA_AW=12)
|
||
reg [11:0] td_wd;
|
||
|
||
// ---- ct_bram:密文字节缓冲区(<=1568 B)。由 E5/E7(压缩 + byteEncode_du/dv)
|
||
// 写入,通过 dbg_ct 抽头回读。----
|
||
wire [10:0] ct_rd_addr;
|
||
wire [7:0] ct_rd_data;
|
||
reg ct_we;
|
||
reg [10:0] ct_wa;
|
||
reg [7:0] ct_wd;
|
||
sd_bram #(.W(8), .D(2048), .A(11)) u_ct_bram (
|
||
.clk(clk),
|
||
.rd_addr(ct_rd_addr), .rd_data(ct_rd_data),
|
||
.wr_en(ct_we), .wr_addr(ct_wa), .wr_data(ct_wd)
|
||
);
|
||
// ct_bram 读取地址:D7 通过 cmp_idx 遍历比较 c';否则为 debug 回读。
|
||
assign ct_rd_addr = (st == ST_DEC_CMP) ? cmp_idx : dbg_ct_idx_i;
|
||
assign dbg_ct_o = ct_rd_data;
|
||
|
||
// ---- c_in_bram:Decaps 输入密文 c(<=1568 B)。在 ST_IDLE 中通过
|
||
// c_in_* 预加载。与 ct_bram(保存计算出的 c')分开保存,
|
||
// 以便 D7 可以比较 c' 与 c,且 D5 J(z||c) 可以读取 c。
|
||
// 读取端口是多路复用的(D5 J 馈送 / D7 比较);
|
||
// 对于 D0,只有加载写入路径存在。
|
||
wire [10:0] cin_rd_addr;
|
||
wire [7:0] cin_rd_data;
|
||
reg [10:0] cin_rd_addr_r; // D5/D7 读取地址(在此之前保持 0)
|
||
sd_bram #(.W(8), .D(2048), .A(11)) u_c_in_bram (
|
||
.clk(clk),
|
||
.rd_addr(cin_rd_addr), .rd_data(cin_rd_data),
|
||
.wr_en(c_in_we), .wr_addr(c_in_addr), .wr_data(c_in_byte)
|
||
);
|
||
// c_in 读取地址:D5 J 组合逻辑地呈现 dj_c_idx(无额外寄存器级),
|
||
// 因此寄存的 BRAM 读取在 1 周期后返回字节,与组装/写回流水线匹配。
|
||
// 其他情况下,寄存的 cin_rd_addr_r(D1 遍历器/空闲)驱动它。
|
||
assign cin_rd_addr = (st == ST_DEC_J) ? dj_c_idx[10:0] :
|
||
(st == ST_DEC_CMP) ? cmp_idx : cin_rd_addr_r;
|
||
|
||
// ================================================================
|
||
// 多项式存储,按 KMAX(最坏情况)大小设计。运行时 k 使用
|
||
// 子范围。槽位布局(每个槽位 = 256 个系数):
|
||
// A_hat[i][j] : 槽位 0 .. k*k-1 索引为 i*k + j
|
||
// s_hat[i] : 槽位 slot_s_rt .. +k-1
|
||
// e_hat[i] : 槽位 slot_e_rt .. +k-1
|
||
// t_hat[i] : 槽位 slot_t_rt .. +k-1
|
||
// NUM_SLOTS = KMAX*KMAX + 3*KMAX = 28(KMAX=4 时)。
|
||
// ================================================================
|
||
localparam NUM_SLOTS = KMAX*KMAX + 3*KMAX;
|
||
localparam SAW = 5; // 槽位地址宽度(>=clog2(28))
|
||
|
||
// ================================================================
|
||
// 3 个 Bank 的系数存储(阶段 2)。原本是异步读取寄存器数组
|
||
// polymem[0:28*256-1];按多项式拆分后,每个成为
|
||
// 带寄存输出的 sd_bram(在最终步骤中推断为 BRAM / ASIC SRAM)。
|
||
// bank_a : A_hat[i][j] 槽位 0..K^2-1 -> D=KMAX*KMAX*256=4096
|
||
// bank_se: s_hat||e_hat 槽位 slot_s.. -> D=2*KMAX*256=2048(相对 0..2K-1)
|
||
// bank_t : t_hat[i] 槽位 slot_t.. -> D=KMAX*256=1024(相对 0..K-1)
|
||
// 地址是基址相对的:bank 索引 = 绝对槽位 - 基槽位。
|
||
// 阶段 2b(进行中):按消费者的寄存预读。目前 Bank
|
||
// 仍是异步寄存器数组;已转换的消费者通过各自
|
||
// 的 1 周期流水线寄存器(== sd_bram 时序)读取。
|
||
// 当某个 Bank 的所有消费者都改为寄存后,该数组将被 sd_bram
|
||
// 替换,其读取端口在(相位不重叠的)消费者之间多路复用。
|
||
// ================================================================
|
||
localparam PA_AW = 12; // bank_a 地址宽度 (4096)
|
||
localparam PSE_AW = 11; // bank_se 地址宽度 (2048)
|
||
localparam PT_AW = 10; // bank_t 地址宽度 (1024)
|
||
|
||
// bank_a: A_hat。读取者 = ST_M 加载 (pm_a) + dbg。写入者 = ST_A。
|
||
// 读取端口按相位多路复用;sd_bram 的内部 rd_addr_r 寄存器是
|
||
// 1 周期读取流水线(替代了显式的 pm_a_rd 寄存器)。写入端口
|
||
// 是组合逻辑驱动的(sd_bram 在上升沿寄存写入,与旧寄存器数组
|
||
// 的非阻塞写入时序匹配)。
|
||
wire [PA_AW-1:0] ba_rd_addr;
|
||
wire [11:0] ba_rd_data;
|
||
wire ba_we;
|
||
wire [PA_AW-1:0] ba_wa;
|
||
wire [11:0] ba_wd;
|
||
sd_bram #(.W(12), .D(1<<PA_AW), .A(PA_AW)) u_bank_a (
|
||
.clk(clk), .rd_addr(ba_rd_addr), .rd_data(ba_rd_data),
|
||
.wr_en(ba_we), .wr_addr(ba_wa), .wr_data(ba_wd)
|
||
);
|
||
// ST_A / ST_ENC_A 写入:当接受时将 snt_coeff 提交到 A_hat[a_slot]。
|
||
// Encaps E6 也通过 byteDecode12 (TDEC) 将 t_hat 写入这里:t_hat[j] 写入
|
||
// bank_a 的槽位 j*K,使得 V 的 MAC 重用 E4 的 u_aslot=u_j*K (u_row=0) 地址。
|
||
// ST_ENC_E2MV 将搬迁的 e2 写入 bank_a[E2_ASLOT] (em_we)。
|
||
// D1 DECOMP 将 v' 写入 bank_a[DEC_VASLOT] (dec_v_we),使得 D3 可以在
|
||
// w-SUB 期间与 bank_t psum 并行读取。
|
||
assign ba_we = ((st == ST_A || st == ST_ENC_A) && a_busy && snt_vo && snt_ack)
|
||
|| td_we || em_we || dec_v_we;
|
||
assign ba_wa = td_we ? td_wa[PA_AW-1:0]
|
||
: em_we ? em_wa[PA_AW-1:0]
|
||
: dec_v_we ? dec_v_wr[PA_AW-1:0]
|
||
: (a_slot*256 + a_widx) & ((1<<PA_AW)-1);
|
||
assign ba_we = ...;
|
||
assign ba_wa = ...;
|
||
assign ba_wd = td_we ? td_wd :
|
||
em_we ? bt_rd_data : // 从 bank_t 相对槽位 0 读取 e2
|
||
dec_v_we ? cd_out : // v' 解压缩后的系数
|
||
snt_coeff;
|
||
|
||
// bank_se: s_hat || e_hat。读取者 = ST_N 加载、ST_M 加载 (pm_b, s_hat[j])、
|
||
// ST_M 累加 (e_hat, j==0)、ST_E dk 半部分、dbg。写入者 = ST_C (CBD)、ST_N
|
||
// 写回(原地 NTT)。所有读取者已寄存;读取端口按相位多路复用
|
||
//(在 ST_M 内部,加载与累加从不重叠)。写入端口
|
||
// 为组合逻辑(ST_C 和 ST_N 是不相交的状态)。
|
||
wire [PSE_AW-1:0] bse_rd_addr;
|
||
wire [11:0] bse_rd_data;
|
||
wire bse_we;
|
||
wire [PSE_AW-1:0] bse_wa;
|
||
wire [11:0] bse_wd;
|
||
sd_bram #(.W(12), .D(1<<PSE_AW), .A(PSE_AW)) u_bank_se (
|
||
.clk(clk), .rd_addr(bse_rd_addr), .rd_data(bse_rd_data),
|
||
.wr_en(bse_we), .wr_addr(bse_wa), .wr_data(bse_wd)
|
||
);
|
||
|
||
// bank_t: t_hat。读取者 = ST_M 累加 (j>0 运行 t_hat) + ST_E ek 半部分 + dbg。
|
||
// 写入者 = ST_M 累加。读取端口按相位多路复用;sd_bram 的 rd_addr_r 是
|
||
// 1 周期读取寄存器。RMW 是安全的:累加读取地址领先写入
|
||
// 地址 1(m_oidx+1 vs m_oidx),因此读取/写入在同一个周期内不会别名,
|
||
// sd_bram 的写优先行为 == 寄存器数组的读旧值。写入端口为组合逻辑。
|
||
wire [PT_AW-1:0] bt_rd_addr;
|
||
wire [11:0] bt_rd_data;
|
||
wire bt_we;
|
||
wire [PT_AW-1:0] bt_wa;
|
||
wire [11:0] bt_wd;
|
||
sd_bram #(.W(12), .D(1<<PT_AW), .A(PT_AW)) u_bank_t (
|
||
.clk(clk), .rd_addr(bt_rd_addr), .rd_data(bt_rd_data),
|
||
.wr_en(bt_we), .wr_addr(bt_wa), .wr_data(bt_wd)
|
||
);
|
||
// bank_t 写入:密钥生成 ST_M 累加,或 Encaps e2(ST_ENC_C c_poly==2K
|
||
// -> bank_t 相对槽位 0,在 C/N/U 阶段空闲)。(TDEC 现在写入 bank_a。)
|
||
wire e2_we = (st == ST_ENC_C) && c_busy && cbd_vo && cbd_ack &&
|
||
(c_poly == {1'b0, k_r, 1'b0}); // c_poly == 2K
|
||
// Encaps E4/E6 bank_t 写入:MAC 部分和(u_sub0,pm_vo 时)和 INTT 原地写回
|
||
//(u_sub1,ntt_vo 时)。均写入 bank_t 相对槽位 UPSUM。ST_ENC_V (E6) 增加
|
||
// V-ADD 写回(psum + e2 + mu)到 UPSUM,通过下面的 u_v_we 实现。
|
||
wire u_psum_we = (st == ST_ENC_U || st == ST_ENC_V || st == ST_DEC_W) && (u_sub == 2'd0) && pm_vo;
|
||
wire u_intt_we = (st == ST_ENC_U || st == ST_ENC_V || st == ST_DEC_W) && (u_sub == 2'd1) && ntt_vo;
|
||
// D1 DECOMP 写回:解码 c2 时 cd_vo 将 v' 写入 bank_a[DEC_VASLOT]。
|
||
wire dec_v_we = (st == ST_DEC_DECOMP) && dec_in_c2 && cd_vo;
|
||
wire [13:0] dec_v_wr = DEC_VASLOT*256 + dec_widx;
|
||
assign bt_we = ((st == ST_M) && pm_vo) || e2_we ||
|
||
u_psum_we || u_intt_we || u_v_we || u_w_we;
|
||
assign bt_wa = e2_we ? (c_widx & ((1<<PT_AW)-1)) :
|
||
u_psum_we ? ((UPSUM*256 + u_oidx) & ((1<<PT_AW)-1)) :
|
||
u_intt_we ? (u_intt_wr[PT_AW-1:0]) :
|
||
u_v_we ? (u_vadd_wr[PT_AW-1:0]) :
|
||
u_w_we ? (u_wsub_wr[PT_AW-1:0]) :
|
||
((m_i*256 + m_oidx) & ((1<<PT_AW)-1));
|
||
assign bt_wd = e2_we ? cbd_modq :
|
||
u_psum_we ? u_accq :
|
||
u_intt_we ? ntt_coeff :
|
||
u_v_we ? u_vq :
|
||
u_w_we ? u_wq :
|
||
m_accq;
|
||
|
||
// Debug 回读(已寄存以改善时序)
|
||
reg [11:0] dbg_coeff_r;
|
||
// 按绝对槽位范围路由 debug 读取(不在 KAT 正确性路径上——
|
||
// 测试平台仅读取 ek/dk BRAM)。A:0..K^2-1;s/e:slot_s..slot_t-1;
|
||
// t:slot_t..。Bank 内索引为 (绝对槽位-基址)*256 + idx。
|
||
wire [13:0] dbg_a_addr = dbg_slot_i*256 + dbg_idx_i;
|
||
wire [13:0] dbg_se_addr = (dbg_slot_i - slot_s_rt)*256 + dbg_idx_i;
|
||
wire [13:0] dbg_t_addr = (dbg_slot_i - slot_t_rt)*256 + dbg_idx_i;
|
||
// bank_a 读取端口:ST_M / Encaps ST_ENC_U MAC 驱动 pm_a 地址;ST_ENC_V
|
||
// MAC 读取 t_hat[j] (u_pm_a_full, u_row=0) 且 ADD 读取 e2 (E2_ASLOT);否则为 dbg。
|
||
assign ba_rd_addr = (st == ST_M) ? pm_a_full[PA_AW-1:0] :
|
||
(st == ST_ENC_U) ? u_pm_a_full[PA_AW-1:0] :
|
||
(st == ST_ENC_V) ?
|
||
((u_sub == 2'd2) ? u_v_e2rd[PA_AW-1:0] // ADD: e2 读取
|
||
: u_pm_a_full[PA_AW-1:0]) : // MAC: t_hat[u_j]
|
||
(st == ST_DEC_W) ?
|
||
((u_sub == 2'd2) ? u_w_vrd[PA_AW-1:0] // SUB: v' 读取
|
||
: u_pm_a_full[PA_AW-1:0]) : // MAC: s_hat[u_j]
|
||
dbg_a_addr[PA_AW-1:0];
|
||
// bank_t 读取端口:ST_M 累加 (t_hat)、ST_E ek 半部分 (byteEncode)、Encaps
|
||
// ST_ENC_U/V + Decaps ST_DEC_W(MAC psum 累加、INTT 加载、或按子相位的
|
||
// ADD/SUB psum 读取)、ST_ENC_E2MV(从相对槽位 0 读取 e2);否则为 dbg。
|
||
assign bt_rd_addr = (st == ST_M) ? m_tacc_full[PT_AW-1:0] :
|
||
(st == ST_E) ? e_rd_full[PT_AW-1:0] :
|
||
(st == ST_ENC_U || st == ST_ENC_V || st == ST_DEC_W) ?
|
||
((u_sub == 2'd0) ? u_psum_full[PT_AW-1:0] : // MAC acc
|
||
(u_sub == 2'd1) ? u_intt_rd[PT_AW-1:0] : // INTT 加载
|
||
u_add_prd[PT_AW-1:0]) : // ADD/SUB psum 读取
|
||
(st == ST_ENC_E2MV) ? em_rd[PT_AW-1:0] : // e2 搬迁读取
|
||
(st == ST_ENC_C2) ? cp_bt_full[PT_AW-1:0] : // C2: v[cp_idx]
|
||
(st == ST_DEC_MENC) ? men_rd[PT_AW-1:0] : // D4: w[men_idx]
|
||
dbg_t_addr[PT_AW-1:0];
|
||
// bank_se 读取端口:ST_N 加载 (s/e NTT)、ST_M 加载 (pm_b s_hat[j]) vs
|
||
// 累加 (e_hat,通过 m_loading 互斥)、ST_E dk 半部分、dbg。
|
||
assign bse_rd_addr = (st == ST_N || st == ST_ENC_N || st == ST_DEC_NTT) ? ntt_rd_full[PSE_AW-1:0] :
|
||
(st == ST_M) ? (m_loading ? pm_b_full[PSE_AW-1:0]
|
||
: m_eacc_full[PSE_AW-1:0]) :
|
||
(st == ST_E) ? e_rd_full[PSE_AW-1:0] :
|
||
(st == ST_ENC_U) ?
|
||
((u_sub == 2'd0) ? u_pm_b_full[PSE_AW-1:0] : // MAC: y_hat[u_j]
|
||
u_add_e1rd[PSE_AW-1:0]) : // ADD: e1[u_row] 读取
|
||
(st == ST_ENC_V) ? u_pm_b_full[PSE_AW-1:0] : // V MAC: y_hat[u_j]
|
||
(st == ST_DEC_W && u_sub == 2'd0) ? u_pm_b_full[PSE_AW-1:0] : // D3 MAC: u_hat[u_j]
|
||
(st == ST_ENC_C1) ? cp_se_full[PSE_AW-1:0] : // C1: u[cp_poly]
|
||
dbg_se_addr[PSE_AW-1:0];
|
||
// bank_se 写入:密钥生成 ST_C CBD (s/e)、Encaps ST_ENC_C CBD (y/e1, c_poly<2K;
|
||
// c_poly==2K 的 e2 写入 bank_t 而非 bank_se)、ST_N/ST_ENC_N NTT 写回、
|
||
// Encaps E4 ADD u 写回 (u_sub==2)。
|
||
// Encaps E4 ADD:将 u[u_row] 写入 bank_se 相对槽位 (K+u_row),覆盖 e1。
|
||
wire u_add_we = (st == ST_ENC_U) && (u_sub == 2'd2) && u_avalid;
|
||
// D1 DECOMP 写回:解码 c1 时 cd_vo 将 u'[dec_poly] 写入
|
||
// bank_se 相对槽位 dec_poly (0..K-1),系数索引为 dec_widx。
|
||
wire dec_u_we = (st == ST_DEC_DECOMP) && !dec_in_c2 && cd_vo;
|
||
wire [13:0] dec_u_wr = {2'b0, dec_poly}*256 + dec_widx;
|
||
assign bse_we = ((st == ST_C) && c_busy && cbd_vo && cbd_ack) ||
|
||
((st == ST_ENC_C) && c_busy && cbd_vo && cbd_ack &&
|
||
(c_poly < {1'b0, k_r, 1'b0})) ||
|
||
(((st == ST_N) || (st == ST_ENC_N) || (st == ST_DEC_NTT)) && ntt_vo) ||
|
||
u_add_we || dec_u_we;
|
||
assign bse_wa = u_add_we ? u_add_uwr[PSE_AW-1:0] :
|
||
dec_u_we ? dec_u_wr[PSE_AW-1:0] :
|
||
(st == ST_N || st == ST_ENC_N || st == ST_DEC_NTT) ? ((n_slot*256 + n_widx) & ((1<<PSE_AW)-1))
|
||
: ((c_poly*256 + c_widx) & ((1<<PSE_AW)-1));
|
||
assign bse_wd = u_add_we ? u_uq :
|
||
dec_u_we ? cd_out :
|
||
(st == ST_N || st == ST_ENC_N || st == ST_DEC_NTT) ? ntt_coeff : cbd_modq;
|
||
always @(posedge clk) begin
|
||
if (dbg_slot_i >= slot_t_rt) dbg_coeff_r <= bt_rd_data; // bank_t (sd_bram)
|
||
else if (dbg_slot_i >= slot_s_rt) dbg_coeff_r <= bse_rd_data; // bank_se (sd_bram)
|
||
else dbg_coeff_r <= ba_rd_data; // bank_a (sd_bram)
|
||
end
|
||
assign dbg_coeff_o = dbg_coeff_r;
|
||
|
||
// ek 和 dk_pke 字节存储器按 KMAX 大小设计。
|
||
localparam EK_MAX = 384*KMAX + 32; // 1568
|
||
localparam DK_MAX = 384*KMAX; // 1536
|
||
|
||
// ek / dk_pke 字节存储于 BRAM (sd_bram: 1R/1W, 1 周期读取延迟)。
|
||
// 每个单读取端口在时间上不重叠地共享:ST_H 组装读取 ek
|
||
//(在 ST_H 中),debug 回读读取 ek/dk(在 ST_DONE 中)。写入端口由
|
||
// ST_E(1 字节/周期)和 rho 尾部复制驱动。
|
||
wire [10:0] ek_rd_addr, dkp_rd_addr;
|
||
wire [7:0] ek_rd_data, dkp_rd_data;
|
||
reg ek_we, dkp_we;
|
||
reg [10:0] ek_wa, dkp_wa;
|
||
reg [7:0] ek_wd, dkp_wd;
|
||
|
||
// ek BRAM 写入端口:密钥生成 ST_E 驱动 ek_we/ek_wa/ek_wd;Encaps 从外部
|
||
// ek_in_* 端口预加载 ek(测试平台在 start_i 前流式输入 ek=pk)。Decaps
|
||
// 在加载时将 dk 的 ek_pke 区域 (dk[384K:768K+32]) 路由至此。三者
|
||
// 从不重叠(预加载在运行前于 ST_IDLE 中完成)。
|
||
wire dk_ld_ekpke = dk_in_we && (dk_in_addr >= dkp_bytes_ld)
|
||
&& (dk_in_addr < dk_ek_end_ld); // ek_pke 区域
|
||
wire dk_ld_dkpke = dk_in_we && (dk_in_addr < dkp_bytes_ld); // dk_pke 区域
|
||
wire [10:0] dk_ek_off = (dk_in_addr - dkp_bytes_ld); // ek 内偏移
|
||
wire ek_we_mux = ek_in_we ? 1'b1 :
|
||
dk_ld_ekpke ? 1'b1 : ek_we;
|
||
wire [10:0] ek_wa_mux = ek_in_we ? ek_in_addr :
|
||
dk_ld_ekpke ? dk_ek_off : ek_wa;
|
||
wire [7:0] ek_wd_mux = ek_in_we ? ek_in_byte :
|
||
dk_ld_ekpke ? dk_in_byte : ek_wd;
|
||
|
||
sd_bram #(.W(8), .D(2048), .A(11)) u_ek_bram (
|
||
.clk(clk),
|
||
.rd_addr(ek_rd_addr), .rd_data(ek_rd_data),
|
||
.wr_en(ek_we_mux), .wr_addr(ek_wa_mux), .wr_data(ek_wd_mux)
|
||
);
|
||
// dk_pke BRAM 写入端口:密钥生成 ST_E(s_hat byteEncode)驱动 dkp_we/wa/wd;
|
||
// Decaps 在加载时将 dk 的 dk_pke 区域 (dk[0:384K]) 路由至此。两者
|
||
// 从不重叠(Decaps 运行前在 ST_IDLE 中预加载)。
|
||
wire dkp_we_mux = dk_ld_dkpke ? 1'b1 : dkp_we;
|
||
wire [10:0] dkp_wa_mux = dk_ld_dkpke ? dk_in_addr[10:0] : dkp_wa;
|
||
wire [7:0] dkp_wd_mux = dk_ld_dkpke ? dk_in_byte : dkp_wd;
|
||
sd_bram #(.W(8), .D(2048), .A(11)) u_dkp_bram (
|
||
.clk(clk),
|
||
.rd_addr(dkp_rd_addr), .rd_data(dkp_rd_data),
|
||
.wr_en(dkp_we_mux), .wr_addr(dkp_wa_mux), .wr_data(dkp_wd_mux)
|
||
);
|
||
|
||
// 完整 dk = dk_pke(dk_bytes) || ek(ek_bytes) || H(ek)(32) || z(32)。
|
||
//(dk_ek_end / dk_hek_end 已在顶部附近与其他大小线一起声明。)
|
||
|
||
// Debug 区域选择用于 dk 回读(组合逻辑区域解码)。
|
||
wire dbgdk_in_dkp = (dbg_dk_idx_i < dk_bytes_rt);
|
||
wire dbgdk_in_ek = (dbg_dk_idx_i >= dk_bytes_rt) && (dbg_dk_idx_i < dk_ek_end);
|
||
|
||
// 读取地址多路复用(在此声明;通过下方 H 阶段寄存器声明后
|
||
// 的 h_blk*136 + h_byte 表达式实现,无函数调用)。
|
||
// dbg_byte_o / dbg_dk_o 是(寄存后的 BRAM 读取数据上的)组合逻辑抽头;
|
||
// 净 1 周期延迟,完全在测试平台的 2 周期读取等待范围内。
|
||
assign dbg_byte_o = dbg_byte_sel_i ? dkp_rd_data : ek_rd_data;
|
||
assign dbg_dk_o = dbgdk_in_dkp ? dkp_rd_data :
|
||
dbgdk_in_ek ? ek_rd_data :
|
||
(dbg_dk_idx_i < dk_hek_end) ? hek_r[(dbg_dk_idx_i - dk_ek_end)*8 +: 8]
|
||
: z_i[(dbg_dk_idx_i - dk_hek_end)*8 +: 8];
|
||
|
||
// ================================================================
|
||
// 顶层 FSM(增量构建)。阶段 2a:仅 G。
|
||
// ================================================================
|
||
localparam ST_IDLE = 5'd0;
|
||
localparam ST_G = 5'd1; // 运行 G(d||K),捕获 rho/sigma
|
||
localparam ST_A = 5'd2; // 通过 SampleNTT 生成 A_hat[i][j]
|
||
localparam ST_C = 5'd3; // 通过 CBD 生成 s[i],e[i]
|
||
localparam ST_N = 5'd4; // 对 s[i],e[i] 进行原地前向 NTT
|
||
localparam ST_M = 5'd5; // 矩阵累加 t_hat = e_hat + sum A o s_hat
|
||
localparam ST_E = 5'd6; // byteEncode12 -> ek/dk BRAM
|
||
localparam ST_H = 5'd7; // 通过多块 SHA3-256 计算 H(ek)
|
||
// ---- Encaps 状态 ----
|
||
localparam ST_ENC_LOAD = 5'd8; // ek 已预加载;占位/稳定
|
||
localparam ST_ENC_H = 5'd9; // 通过多块 SHA3-256 计算 H(ek)(重用 ST_H 逻辑)
|
||
localparam ST_ENC_G = 5'd10; // (K,r) = G(m || H(ek)),64 字节单块
|
||
localparam ST_ENC_A = 5'd11; // 重新生成 A_hat(U 中使用转置)
|
||
localparam ST_ENC_TDEC = 5'd12; // byteDecode12:ek -> t_hat(bank_a 槽位 j*K)
|
||
localparam ST_ENC_C = 5'd13; // 通过 CBD 采样 y,e1,e2(eta1/eta2)
|
||
localparam ST_ENC_N = 5'd14; // 对 y 进行原地前向 NTT
|
||
localparam ST_ENC_U = 5'd15; // u = INTT(sum A^T o y_hat) + e1
|
||
localparam ST_ENC_C1 = 5'd16; // Compress_du + byteEncode_du -> ct c1
|
||
localparam ST_ENC_V = 5'd17; // v = INTT(sum t_hat o y_hat) + e2 + mu
|
||
localparam ST_ENC_C2 = 5'd18; // Compress_dv + byteEncode_dv -> ct c2
|
||
localparam ST_ENC_E2MV = 5'd19; // 搬迁 e2 bank_t[0] -> bank_a[E2_ASLOT]
|
||
// ---- Decaps 状态 ----
|
||
localparam ST_DEC_LOAD = 5'd20; // dk/c 已流式输入;解析/稳定(D0)
|
||
localparam ST_DEC_DECOMP = 5'd21; // D1:byteDecode_d + 解压缩 c1->u', c2->v'
|
||
localparam ST_DEC_SDEC = 5'd22; // D2:byteDecode12 dk_pke -> s_hat(bank_a 槽位 j*K)
|
||
localparam ST_DEC_NTT = 5'd23; // D2:u_hat[i] = NTT(u'[i]) 原地(bank_se 相对 i)
|
||
localparam ST_DEC_W = 5'd24; // D3:w = v' - INTT(sum_j s_hat[j] o u_hat[j])
|
||
localparam ST_DEC_MENC = 5'd25; // D4:m' = byteEncode_1(Compress_1(w))
|
||
localparam ST_DEC_G = 5'd26; // D5:(K',r') = G(m' || h),SHA3-512 单块
|
||
localparam ST_DEC_J = 5'd27; // D5:K-bar = J(z || c),多块 SHAKE256
|
||
localparam ST_DEC_CMP = 5'd28; // D7:c' == c 比较 + 隐式拒绝 ss 选择
|
||
localparam ST_DONE = 5'd31;
|
||
|
||
reg [4:0] st, st_next;
|
||
reg [255:0] rho_r, sigma_r;
|
||
|
||
// A 生成簿记:显式 i/j 计数器(避免运行时除法)
|
||
reg [2:0] a_i; // 行 0..k-1
|
||
reg [2:0] a_j; // 列 0..k-1
|
||
reg [4:0] a_pair; // 已完成的 k*k 对计数(用于结束测试)
|
||
reg [7:0] a_widx; // 当前多项式内的写入索引 0..255
|
||
reg a_busy; // 当前对的请求被接受后为 1(选通收集)
|
||
wire [SAW-1:0] a_slot = a_i*k_r + a_j; // A_hat[i][j] 槽位 = i*k + j
|
||
|
||
// C 生成簿记:2*k 个多项式(s[0..k-1] 然后 e[0..k-1])
|
||
reg [4:0] c_poly; // 0..2k
|
||
reg [7:0] c_widx;
|
||
reg c_busy;
|
||
wire [7:0] c_nonce = {3'b0, c_poly}; // s:0..k-1 e:k..2k-1 == nonce
|
||
// 槽位:c_poly < k -> s_hat[c_poly],否则 e_hat[c_poly-k]
|
||
wire [SAW-1:0] c_slot = (c_poly < {2'b0, k_r}) ? (slot_s_rt + c_poly)
|
||
: (slot_e_rt + (c_poly - {2'b0, k_r}));
|
||
|
||
assign busy_o = (st != ST_IDLE);
|
||
assign done_o = (st == ST_DONE);
|
||
assign dbg_rho_o = rho_r;
|
||
assign dbg_sigma_o = sigma_r;
|
||
assign dbg_r_o = r_r;
|
||
assign dbg_hek_o = hek_r;
|
||
// Decaps 抽头:m' 来自 D4(写入 m_r,在 D6 重加密中被 V/mu 重用);
|
||
// 加载时从 dk 解析的 z/h。
|
||
assign dbg_mprime_o = m_r;
|
||
assign dbg_kbar_o = kbar_r;
|
||
assign dbg_decz_o = z_r;
|
||
assign dbg_dech_o = hek_r; // Decaps 在加载时将 dk 的 H(ek) 解析到 hek_r
|
||
|
||
// ---- sha3_top 处于 G 模式:data_i = {K_byte, d}(d 字节 0 在 [7:0] 中)----
|
||
reg sha3_valid;
|
||
wire sha3_ready;
|
||
wire [511:0] sha3_hash;
|
||
wire sha3_vo;
|
||
reg sha3_ack; // 消费者准备接收哈希
|
||
wire [511:0] kg_g_data = {248'b0, 5'b0, k_r, d_i}; // 密钥生成 G:[263:256]=k, [255:0]=d
|
||
wire [511:0] enc_g_data = {hek_r, m_r}; // Encaps G:m || H(ek),64 字节
|
||
wire [511:0] dec_g_data = {hek_r, m_r}; // Decaps D5 G:m' || h,64 字节
|
||
wire [511:0] g_data = (st == ST_ENC_G) ? enc_g_data :
|
||
(st == ST_DEC_G) ? dec_g_data : kg_g_data;
|
||
|
||
// ================================================================
|
||
// 共享 keccak_core + 相位多路复用(3 个消费者 -> 1 个核心)
|
||
//
|
||
// G/H (u_sha3)、SampleNTT (u_snt) 和 CBD (u_cbd) 各自需要一个 Keccak
|
||
// 置换,但它们在不相交的顶层 FSM 阶段运行(分别为 ST_G/ST_H、ST_A、
|
||
// ST_C),因此同时最多只有一个活跃。一个 keccak_core
|
||
// 服务所有三者:kc_state_i/kc_valid_i 按相位多路复用;kc_valid_o
|
||
// 广播但按消费者选通,这样不活跃的消费者永远不会
|
||
// 锁存为另一个消费者准备的置换结果(采样器无条件地
|
||
// 在其 kc_valid_o 输入上锁存挤压状态)。
|
||
// ================================================================
|
||
wire [1599:0] kc_state_o; // 共享核心输出(给所有消费者)
|
||
wire kc_valid_o; // 共享核心输出有效
|
||
wire kc_ready_o; // 共享核心输入就绪
|
||
|
||
// 每个消费者驱动到核心
|
||
wire [1599:0] sha3_kc_state_i, snt_kc_state_i, cbd_kc_state_i;
|
||
wire sha3_kc_valid_i, snt_kc_valid_i, cbd_kc_valid_i;
|
||
/* verilator lint_off UNUSED */
|
||
wire sha3_kc_ready_i, snt_kc_ready_i, cbd_kc_ready_i; // 均为 1'b1
|
||
/* verilator lint_on UNUSED */
|
||
|
||
// 相位选择(互斥)。Encaps 增加 ST_ENC_H/G (sha3)、
|
||
// ST_ENC_A (snt)、ST_ENC_C (cbd)。
|
||
wire sel_sha3 = (st == ST_G) || (st == ST_H) ||
|
||
(st == ST_ENC_H) || (st == ST_ENC_G) ||
|
||
(st == ST_DEC_G) || (st == ST_DEC_J);
|
||
wire sel_snt = (st == ST_A) || (st == ST_ENC_A);
|
||
wire sel_cbd = (st == ST_C) || (st == ST_ENC_C);
|
||
|
||
// 选通输出有效:只有活跃消费者看到 kc_valid_o
|
||
wire kc_valid_o_sha3 = kc_valid_o & sel_sha3;
|
||
wire kc_valid_o_snt = kc_valid_o & sel_snt;
|
||
wire kc_valid_o_cbd = kc_valid_o & sel_cbd;
|
||
|
||
// 输入多路复用:将活跃消费者的请求路由到核心
|
||
wire [1599:0] kc_state_i_mux = sel_snt ? snt_kc_state_i :
|
||
sel_cbd ? cbd_kc_state_i :
|
||
sha3_kc_state_i;
|
||
wire kc_valid_i_mux = sel_snt ? snt_kc_valid_i :
|
||
sel_cbd ? cbd_kc_valid_i :
|
||
sel_sha3 ? sha3_kc_valid_i : 1'b0;
|
||
|
||
keccak_core #(.ROUNDS(24)) u_keccak (
|
||
.clk(clk), .rst_n(rst_n),
|
||
.state_i(kc_state_i_mux),
|
||
.valid_i(kc_valid_i_mux),
|
||
.ready_o(kc_ready_o),
|
||
.state_o(kc_state_o),
|
||
.valid_o(kc_valid_o),
|
||
.ready_i(1'b1) // 消费者始终接收 (kc_ready_i=1)
|
||
);
|
||
|
||
// G/H/J 共享一个 sha3_top。单块 (mb_en=0):密钥生成 G (ST_G, mode 00)、
|
||
// Encaps G (ST_ENC_G, mode 11)、Decaps D5 G (ST_DEC_G, mode 11)。多块
|
||
// 吸收 (mb_en=1):H(ek) (ST_H/ST_ENC_H, SHA3-256 填充) 和 Decaps D5 J
|
||
// (ST_DEC_J, SHAKE256 填充,输入为 z||c)。mb_* 输入按相位多路复用。
|
||
wire sha3_mb_en = (st == ST_H) || (st == ST_ENC_H) || (st == ST_DEC_J);
|
||
wire [1:0] sha3_mode = (st == ST_ENC_G || st == ST_DEC_G) ? 2'b11 : 2'b00;
|
||
// 多块馈送多路复用:J (ST_DEC_J) 驱动 dj_*,否则 H 驱动 h_*。
|
||
wire [1087:0] mb_block_mux = (st == ST_DEC_J) ? dj_block_r : h_block_r;
|
||
wire mb_valid_mux = (st == ST_DEC_J) ? dj_mbvalid : h_mbvalid;
|
||
wire mb_last_mux = (st == ST_DEC_J) ? dj_mblast : h_mblast;
|
||
wire mb_ack_mux = (st == ST_DEC_J) ? dj_ack : h_ack;
|
||
sha3_top_shared u_sha3 (
|
||
.clk(clk), .rst_n(rst_n),
|
||
.mode(sha3_mode), // G = SHA3-512(仅在 mb_en=0 时使用)
|
||
.data_i(g_data),
|
||
.valid_i(sha3_valid),
|
||
.ready_o(sha3_ready),
|
||
.hash_o(sha3_hash),
|
||
.valid_o(sha3_vo),
|
||
.ready_i(sha3_mb_en ? mb_ack_mux : sha3_ack),
|
||
.mb_en(sha3_mb_en),
|
||
.mb_block_i(mb_block_mux),
|
||
.mb_valid_i(mb_valid_mux),
|
||
.mb_last_i(mb_last_mux),
|
||
.mb_ready_o(h_mbready),
|
||
// 共享 keccak_core 接口(在下方的多路复用器中按相位选通)
|
||
.kc_state_o(kc_state_o),
|
||
.kc_valid_o(kc_valid_o_sha3),
|
||
.kc_ready_o(kc_ready_o),
|
||
.kc_state_i(sha3_kc_state_i),
|
||
.kc_valid_i(sha3_kc_valid_i),
|
||
.kc_ready_i(sha3_kc_ready_i)
|
||
);
|
||
|
||
// ---- 多块 H(ek) 状态(SHA3-256,6/9/12 块);馈送到共享 u_sha3 ----
|
||
reg [1087:0] h_block_r; // 当前预填充的速率块
|
||
reg h_mbvalid;
|
||
reg h_mblast;
|
||
wire h_mbready;
|
||
wire [511:0] h_hash;
|
||
wire h_vo;
|
||
reg h_ack;
|
||
reg [255:0] hek_r; // 捕获的 H(ek)
|
||
reg [3:0] h_blk; // 0..H_NBLK-1 块索引(K=4 时最多 11)
|
||
reg [7:0] h_byte; // 0..136 正在呈现的字节地址(组装)
|
||
reg [1:0] h_phase; // 0=组装 1=馈送 2=等待置换 3=完成
|
||
// ek BRAM 读取是寄存的(1 周期延迟);组装为 h_byte 呈现地址,
|
||
// 并将(上一周期呈现的地址对应的)到达字节写入 h_block_r。
|
||
// 写回流水线寄存器:
|
||
reg h_wb_vld; // 本周起有字节到达
|
||
reg [7:0] h_wb_idx; // 在 136 字节块中的位置
|
||
reg [11:0] h_wb_g; // 全局 ek 字节索引
|
||
reg [7:0] h_wb_pad; // 当 g 超出 ek 范围时使用的填充常量
|
||
reg h_wb_inek; // 当 g 在 ek 范围内时为 1(使用 BRAM 数据)
|
||
|
||
// ---- Decaps D5 J(z||c) 多块 SHAKE256 状态 ----
|
||
// 消息 = z(32 B,来自 z_r)|| c(ct_bytes_rt B,来自 c_in_bram)。速率为 136。
|
||
// SHAKE256 填充:msg_len 处的字节为 0x1F,最后一块的最后一个字节或上 0x80。
|
||
// 重用共享 u_sha3 的 mb_* 端口(上面由 ST_DEC_J 多路复用)。
|
||
reg [1087:0] dj_block_r; // 当前预填充的速率块
|
||
reg dj_mbvalid;
|
||
reg dj_mblast;
|
||
reg dj_ack;
|
||
reg [3:0] dj_blk; // 块索引 0..DJ_NBLK-1(z||c 最多 ~1600B -> <=12 块)
|
||
reg [7:0] dj_byte; // 0..136 正在组装的字节
|
||
reg [1:0] dj_phase; // 0=组装 1=馈送 2=等待置换 3=完成
|
||
reg dj_done;
|
||
// 写回流水线(c_in_bram 寄存读取,1 周期延迟)
|
||
reg dj_wb_vld;
|
||
reg [7:0] dj_wb_idx; // 在 136 字节块中的位置
|
||
reg dj_wb_inc; // 全局字节 g 在 c 范围内时为 1(使用 BRAM)
|
||
reg dj_wb_inz; // g < 32 时为 1(使用 z_r 字节)
|
||
reg [7:0] dj_wb_pad; // g 超出消息范围时的填充常量
|
||
reg [4:0] dj_wb_zidx; // 当 inz 时的 z 字节索引 (g)
|
||
// J 消息长度 = 32 (z) + ct_bytes_rt;总填充块数。
|
||
wire [11:0] dj_msglen = 12'd32 + {1'b0, ct_bytes_rt};
|
||
wire [11:0] dj_last_byte = (dj_msglen / 12'd136) * 12'd136 + 12'd135; // 最后一块的最后一个字节
|
||
wire [3:0] dj_nblk = (dj_msglen / 12'd136) + 4'd1;
|
||
// 本周起呈现的地址的全局字节索引 (组装)
|
||
wire [11:0] dj_g = {4'd0, dj_blk} * 12'd136 + {4'd0, dj_byte};
|
||
// c_in_bram 字节索引(当 g>=32 时):g-32
|
||
wire [11:0] dj_c_idx = dj_g - 12'd32;
|
||
// 全局字节 g 的 SHAKE256 填充常量
|
||
function [7:0] dj_padconst(input [11:0] g);
|
||
begin
|
||
if (g == dj_last_byte && g == dj_msglen) dj_padconst = 8'h9f; // 0x1F|0x80
|
||
else if (g == dj_msglen) dj_padconst = 8'h1f;
|
||
else if (g == dj_last_byte) dj_padconst = 8'h80;
|
||
else dj_padconst = 8'h00;
|
||
end
|
||
endfunction
|
||
|
||
// h_hash / h_vo 现在由上述共享 u_sha3 提供(ST_H 期间 mb_en=1)。
|
||
// 它们与单核心输出的别名相同;下方的 H 消费者逻辑
|
||
// 已经根据 st==ST_H 选通,且 u_sha3 的 valid_o/hash_o 由 mb 选择。
|
||
assign h_hash = sha3_hash;
|
||
assign h_vo = sha3_vo;
|
||
|
||
// SHA3-256 计算 ek (ek_bytes_rt 字节):速率为 136。填充长度 = h_nblk_rt*136。
|
||
// 填充:字节 ek_bytes_rt = 0x06(域 + 首填充位),最后字节或上 0x80。
|
||
// 块 blk 的字节 b (0..135):全局 g = blk*136 + b。
|
||
// ek 字节来自 ek BRAM(寄存读取);只有填充/零字节
|
||
// 是常量,由 h_padconst 返回。读取运行时 ek_bytes_rt/h_last_rt。
|
||
function [7:0] h_padconst(input [3:0] blk, input [7:0] b);
|
||
integer g;
|
||
begin
|
||
g = blk*136 + b;
|
||
if (g == h_last_rt && g == ek_bytes_rt) h_padconst = 8'h86; // 0x06|0x80
|
||
else if (g == ek_bytes_rt) h_padconst = 8'h06;
|
||
else if (g == h_last_rt) h_padconst = 8'h80;
|
||
else h_padconst = 8'h00;
|
||
end
|
||
endfunction
|
||
|
||
// ST_H 组装中当前呈现的地址的全局 ek 字节索引。
|
||
wire [11:0] h_g_addr = {8'd0, h_blk} * 12'd136 + {4'd0, h_byte};
|
||
|
||
// ek BRAM 读取地址多路复用:ST_H 组装驱动它;否则为 debug 回读。
|
||
// dbg_dk ek 区域优先(其循环在 ek 循环之后运行),因此
|
||
// 单读取端口服务于 dbg_byte_o(ek 循环)然后 dbg_dk_o(dk 循环)。
|
||
wire [11:0] dbgdk_ek_off = dbg_dk_idx_i - dk_bytes_rt; // ek 区域内的偏移
|
||
assign ek_rd_addr = (st == ST_H || st == ST_ENC_H) ? h_g_addr[10:0] :
|
||
(st == ST_ENC_LOAD) ? rl_ek_off[10:0] : // rho 加载
|
||
(st == ST_ENC_TDEC) ? td_ekaddr[10:0] : // byteDecode12
|
||
dbgdk_in_ek ? dbgdk_ek_off[10:0]
|
||
: dbg_byte_idx_i;
|
||
// dkp BRAM 读取地址多路复用:D2 byteDecode12 (ST_DEC_SDEC) 通过 td_ekaddr
|
||
// (poly*384 + trip*3 + ph) 遍历 dk_pke;否则为 dbg_byte (sel=1) / dbg_dk。
|
||
assign dkp_rd_addr = (st == ST_DEC_SDEC) ? td_ekaddr[10:0] :
|
||
dbg_byte_sel_i ? dbg_byte_idx_i : dbg_dk_idx_i[10:0];
|
||
|
||
// ---- sample_ntt_sync: Â[i][j] = SampleNTT(rho || j || i) ----
|
||
reg snt_valid;
|
||
wire snt_ready;
|
||
wire [11:0] snt_coeff;
|
||
wire snt_vo;
|
||
wire snt_last;
|
||
reg snt_ack; // 接收系数
|
||
|
||
sample_ntt_sync_shared #(.K(KMAX)) u_snt (
|
||
.clk(clk), .rst_n(rst_n),
|
||
.rho_i(rho_r),
|
||
.k_i(k_r),
|
||
.i_idx(a_i[1:0]),
|
||
.j_idx(a_j[1:0]),
|
||
.valid_i(snt_valid),
|
||
.ready_o(snt_ready),
|
||
.coeff_o(snt_coeff),
|
||
.valid_o(snt_vo),
|
||
.ready_i(snt_ack),
|
||
.last_o(snt_last),
|
||
// 共享 keccak_core 接口
|
||
.kc_state_o(kc_state_o),
|
||
.kc_valid_o(kc_valid_o_snt),
|
||
.kc_ready_o(kc_ready_o),
|
||
.kc_state_i(snt_kc_state_i),
|
||
.kc_valid_i(snt_kc_valid_i),
|
||
.kc_ready_i(snt_kc_ready_i)
|
||
);
|
||
|
||
// ---- sample_cbd_sync: s[i]=CBD3(PRF(sigma,i)), e[i]=CBD3(PRF(sigma,K+i)) ----
|
||
reg cbd_valid;
|
||
wire cbd_ready;
|
||
wire [11:0] cbd_coeff; // 12 位有符号(二进制补码)
|
||
wire cbd_vo;
|
||
wire cbd_last;
|
||
reg cbd_ack;
|
||
|
||
// CBD 输入在 KeyGen 和 Encaps 之间多路复用:
|
||
// KeyGen ST_C: seed=sigma, eta=eta1(所有多项式), nonce=c_poly。
|
||
// Encaps ST_ENC_C: seed=r, nonce=c_poly; eta=eta1(y, c_poly<K 时),
|
||
// eta2(e1/e2, c_poly>=K 时)。nonce 序列 0..2K 与 FIPS 一致。
|
||
wire cbd_enc = (st == ST_ENC_C);
|
||
wire [255:0] cbd_seed = cbd_enc ? r_r : sigma_r;
|
||
wire [1:0] cbd_eta = cbd_enc ? ((c_poly < {2'b0, k_r}) ? eta1_rt : eta2_rt)
|
||
: eta1_rt;
|
||
sample_cbd_sync_shared u_cbd (
|
||
.clk(clk), .rst_n(rst_n),
|
||
.seed_i(cbd_seed),
|
||
.nonce_i(c_nonce),
|
||
.eta_i(cbd_eta),
|
||
.valid_i(cbd_valid),
|
||
.ready_o(cbd_ready),
|
||
.coeff_o(cbd_coeff),
|
||
.valid_o(cbd_vo),
|
||
.ready_i(cbd_ack),
|
||
.last_o(cbd_last),
|
||
// 共享 keccak_core 接口
|
||
.kc_state_o(kc_state_o),
|
||
.kc_valid_o(kc_valid_o_cbd),
|
||
.kc_ready_o(kc_ready_o),
|
||
.kc_state_i(cbd_kc_state_i),
|
||
.kc_valid_i(cbd_kc_valid_i),
|
||
.kc_ready_i(cbd_kc_ready_i)
|
||
);
|
||
|
||
// 有符号(二进制补码)-> [0,Q):负数时加 Q
|
||
wire [11:0] cbd_modq = cbd_coeff[11] ? (cbd_coeff + 12'd3329) : cbd_coeff;
|
||
|
||
// ---- ntt_core: 对 s[i],e[i] 进行原地前向 NTT(mode=0, 无缩放)----
|
||
// N 阶段簿记:处理槽位 S0,S1,E0,E1(= SLOT_S0 + n_slot)。
|
||
reg [4:0] n_slot; // 0..2K(先处理 s_hat[0..K-1],再处理 e_hat[0..K-1])
|
||
reg [8:0] n_ridx; // 加载预读指针 0..256(领先消耗 1 周期)
|
||
reg [7:0] n_widx; // 输出写入索引 0..255
|
||
reg n_valid; // 向 ntt_core 馈送系数(比 n_ridx 延迟 1 周期)
|
||
reg n_loading; // 向 bank_se 呈现加载地址时为 1
|
||
reg n_pending; // 等待 ntt_core IDLE 以启动下一个槽位
|
||
wire [SAW-1:0] n_slot_addr = slot_s_rt + n_slot; // s_hat 和 e_hat 连续
|
||
// NTT 槽位数:KeyGen 处理 2K (s,e);Encaps 处理 K(仅 y)。
|
||
wire [4:0] n_slot_max = (st == ST_ENC_N || st == ST_DEC_NTT) ? {2'b0, k_r} : {1'b0, k_r, 1'b0};
|
||
|
||
wire ntt_ready;
|
||
wire [11:0] ntt_coeff;
|
||
wire ntt_vo;
|
||
wire ntt_done;
|
||
// NTT 加载的 bank_se 读取地址(相对槽位 = n_slot);sd_bram
|
||
// 将其寄存到 bse_rd_data,1 周期后送入 ntt_core。
|
||
wire [13:0] ntt_rd_full = n_slot*256 + n_ridx[7:0];
|
||
// ntt_core 输入多路复用:KeyGen/Encaps 前向 NTT 送入 bse_rd_data(mode 0);
|
||
// Encaps E4/E6 INTT 子阶段以 mode 1 送入 psum (bt_rd_data)。
|
||
wire u_intt_act = (st == ST_ENC_U || st == ST_ENC_V || st == ST_DEC_W) && (u_sub == 2'd1);
|
||
wire [11:0] ntt_in = u_intt_act ? bt_rd_data : bse_rd_data;
|
||
wire ntt_vin = u_intt_act ? u_nvalid : n_valid;
|
||
wire ntt_mode = u_intt_act ? 1'b1 : 1'b0;
|
||
|
||
ntt_core u_ntt (
|
||
.clk(clk), .rst_n(rst_n),
|
||
.coeff_in(ntt_in),
|
||
.valid_i(ntt_vin),
|
||
.ready_o(ntt_ready),
|
||
.mode(ntt_mode), // 0 = 前向 (NTT), 1 = 逆向 (INTT, x3303)
|
||
.coeff_out(ntt_coeff),
|
||
.valid_o(ntt_vo),
|
||
.ready_i(1'b1), // 始终接收输出
|
||
.done_o(ntt_done)
|
||
);
|
||
|
||
// ---- poly_mul_sync: t_hat[i] = e_hat[i] + sum_j A_hat[i][j] o s_hat[j] ----
|
||
// M 阶段簿记。对每对 (i,j):加载 256 对 (A,s_hat),然后
|
||
// 将 256 个乘积累加到 T_i(j==0 时从 E_i 初始化,否则从运行的 T_i 继续)。
|
||
reg [2:0] m_i; // 行 0..K(需要达到 K 才能退出)
|
||
reg [2:0] m_j; // 列 0..K-1
|
||
reg [8:0] m_ld; // 加载索引 0..256
|
||
reg [7:0] m_oidx; // 输出/累加索引 0..255
|
||
reg m_loading; // 向 poly_mul 流式传输系数对时为 1
|
||
reg m_pending; // 等待 poly_mul IDLE 再进行下一个 (i,j)
|
||
|
||
// ---- 阶段 2f: byteEncode12 串行化器 ----
|
||
// 打包每个多项式(2 个系数 -> 3 个字节,12 位 LSB-first)。ek = t_hat[0..K-1]
|
||
// 字节 || rho;dk_pke = s_hat[0..K-1] 字节。遍历每个多项式的系数对。
|
||
reg [4:0] e_poly; // 0..2K-1: [0,K) = t_hat -> ek; [K,2K) = s_hat -> dk_pke
|
||
reg [7:0] e_pair; // 0..127 多项式内的系数对
|
||
reg [9:0] e_rho; // 0..31 rho 字节复制索引(ek 尾部)
|
||
reg e_done; // 串行化完成
|
||
// 源多项式槽位:ek 半部分为 t_hat[e_poly],dk 半部分为 s_hat[e_poly-K]
|
||
wire e_is_dk = (e_poly >= {1'b0, k_r});
|
||
wire [4:0] e_pidx = e_is_dk ? (e_poly - {1'b0, k_r}) : e_poly; // 目标内索引
|
||
// 寄存的单端口读取(sd_bram 时序)。每周期一次 bank 读取:
|
||
// ek 半部分读取 bank_t (t_hat),dk 半部分读取 bank_se (s_hat)。一个
|
||
// 系数对的两个系数在 4 周期微相 e_ph 中串行化:
|
||
// 0 = 取回 c0
|
||
// 1 = c0 就绪:写入 b0,保存 c0[11:8],取回 c1
|
||
// 2 = c1 就绪:写入 b1,保存 c1[11:4]
|
||
// 3 = 写入 b2,推进到下一个系数对
|
||
reg [1:0] e_ph; // 每系数对微相 0..3
|
||
reg [3:0] e_c0_hi; // 为 b1 保存的 c0[11:8]
|
||
reg [7:0] e_c1_hi; // 为 b2 保存的 c1[11:4]
|
||
wire e_rd_half = (e_ph == 2'd1); // ph0 -> c0, ph1 -> c1
|
||
wire [13:0] e_rd_full = e_pidx*256 + {e_pair, e_rd_half}; // ST_E 中 bse/bt 读取地址
|
||
// dk 半部分读取 bank_se (bse_rd_data),ek 半部分读取 bank_t (bt_rd_data);
|
||
// 两者在各自的 sd_bram 内寄存,具有相同的 1 周期延迟,因此
|
||
// 这里选择上一周期呈现的地址对应的系数。
|
||
wire [11:0] e_rd_coeff = e_is_dk ? bse_rd_data : bt_rd_data;
|
||
// byteEncode 写入目标存储器内的字节偏移:pair*3 + 字节索引。
|
||
wire [11:0] e_base = e_pidx * 12'd384; // 多项式索引 *384(=128 对*3)
|
||
wire [11:0] e_boff = e_base + {e_pair, 1'b0} + {2'b0, e_pair}; // pair*3
|
||
wire [1:0] e_wb = e_ph - 2'd1; // ph1->字节0, ph2->字节1, ph3->字节2
|
||
wire [7:0] e_wbyte = (e_ph == 2'd1) ? e_rd_coeff[7:0] // b0 = c0[7:0]
|
||
: (e_ph == 2'd2) ? {e_rd_coeff[3:0], e_c0_hi} // b1 = {c1[3:0],c0[11:8]}
|
||
: e_c1_hi; // b2 = c1[11:4]
|
||
|
||
wire [SAW-1:0] m_aslot = m_i*k_r + m_j; // A_hat[i][j] 槽位 = i*k + j
|
||
wire [SAW-1:0] m_sslot = slot_s_rt + m_j; // s_hat[j]
|
||
wire [SAW-1:0] m_eslot = slot_e_rt + m_i; // e_hat[i]
|
||
wire [SAW-1:0] m_tslot = slot_t_rt + m_i; // t_hat[i]
|
||
|
||
// ================================================================
|
||
// E4: u[i] = INTT(sum_j A^T[i][j] o y_hat[j]) + e1[i](Encaps ST_ENC_U)
|
||
// 每行 i,三个子阶段 (u_sub):
|
||
// 0 MAC : sum_j A_hat[j][i] o y_hat[j](转置)-> psum bank_t[UPSUM]
|
||
// 1 INTT : INTT(psum) mode=1 原地在 bank_t[UPSUM] 中
|
||
// 2 ADD : u[i][w] = psum[w] + e1[i][w] mod Q -> bank_se 相对 (K+i)(覆盖 e1)
|
||
// y_hat (bank_se 0..K-1) 保留供 V 使用。重用共享的 u_pmul + u_ntt。
|
||
// ================================================================
|
||
localparam UPSUM = 10'd1; // NTT 域 psum 的 bank_t 相对槽位
|
||
reg [2:0] u_row; // 输出行 i 0..K-1
|
||
reg [1:0] u_sub; // 0=MAC 1=INTT 2=ADD
|
||
// MAC 簿记(镜像 ST_M)
|
||
reg [2:0] u_j; // 项列 j 0..K-1
|
||
reg [8:0] u_ld; // 加载预读 0..256
|
||
reg [7:0] u_oidx; // 累加索引 0..255
|
||
reg u_loading; // 向 poly_mul 流式传输系数对
|
||
reg u_pending; // 等待 poly_mul IDLE 再处理下一个 j
|
||
reg u_j0q; // (u_j==0) 延迟 1 周期(首项=0 选择)
|
||
// INTT 簿记(镜像 ST_N)
|
||
reg [8:0] u_ridx; // INTT 加载预读 0..256
|
||
reg [7:0] u_widx; // INTT 输出索引 0..255
|
||
reg u_nvalid; // 向 ntt_core 馈送 psum (mode=1)
|
||
reg u_nloading; // 呈现 INTT 加载地址
|
||
reg u_npending; //(未使用的占位,保持对称)
|
||
// ADD 簿记
|
||
reg [8:0] u_aidx; // ADD 预读 0..256
|
||
reg [7:0] u_awidx; // ADD 写入索引 0..255
|
||
reg u_avalid; // ADD 写入使能流水线
|
||
// MAC 地址:A^T -> A_hat[u_j][u_row] 槽位 = u_j*k+u_row; y_hat[u_j] 相对 u_j
|
||
wire [SAW-1:0] u_aslot = u_j*k_r + u_row;
|
||
wire [13:0] u_pm_a_full = u_aslot*256 + u_ld[7:0]; // bank_a
|
||
wire [13:0] u_pm_b_full = u_j*256 + u_ld[7:0]; // bank_se y_hat[u_j]
|
||
wire [7:0] u_acc_radr = pm_vo ? (u_oidx + 8'd1) : u_oidx;
|
||
wire [13:0] u_psum_full = UPSUM*256 + u_acc_radr; // bank_t psum 累加地址 (MAC)
|
||
wire [11:0] u_acc_src = u_j0q ? 12'd0 : bt_rd_data; // 首项初始化 0
|
||
wire [12:0] u_sum = {1'b0, u_acc_src} + {1'b0, pm_coeff};
|
||
wire [11:0] u_accq = (u_sum >= 13'd3329) ? (u_sum - 13'd3329) : u_sum[11:0];
|
||
// INTT 加载地址(psum 读取)+ 原地写回 bank_t[UPSUM]
|
||
wire [13:0] u_intt_rd = UPSUM*256 + u_ridx[7:0];
|
||
wire [13:0] u_intt_wr = UPSUM*256 + u_widx;
|
||
// ADD:读取 psum (bank_t) + e1 (bank_se K+u_row),写入 u 覆盖 e1(预读 1)
|
||
wire [13:0] u_add_prd = UPSUM*256 + u_aidx[7:0]; // bank_t psum
|
||
wire [13:0] u_add_e1rd = ({2'b0,k_r}+{2'b0,u_row})*256 + u_aidx[7:0]; // bank_se e1(领先)
|
||
wire [13:0] u_add_uwr = ({2'b0,k_r}+{2'b0,u_row})*256 + u_awidx; // bank_se u(写入)
|
||
wire [12:0] u_usum = {1'b0, bt_rd_data} + {1'b0, bse_rd_data}; // psum + e1
|
||
wire [11:0] u_uq = (u_usum >= 13'd3329) ? (u_usum - 13'd3329) : u_usum[11:0];
|
||
|
||
// ================================================================
|
||
// E6: v = INTT(sum_j t_hat[j] o y_hat[j]) + e2 + mu(Encaps ST_ENC_V)。
|
||
// 重用 u_* MAC/INTT/ADD 机,u_row 固定为 0(单个输出
|
||
// 多项式)。与 E4 的区别:
|
||
// - MAC 从 bank_a 槽位 j*K(== u_aslot=u_j*K, u_row=0)读取 t_hat[j],
|
||
// 因此 bank_a MAC 地址不变。
|
||
// - ADD 计算 psum + e2 + mu(而非 psum + e1);e2 位于 bank_a 槽位
|
||
// E2_ASLOT(在 ST_ENC_E2MV 中从 bank_t[0] 搬迁而来),v 原地写回
|
||
// bank_t[UPSUM]。
|
||
// - mu[w] = Decompress_1(m 比特 w) = m_r[w] ? 1665 : 0(1665 = round(Q/2))。
|
||
// u_row_max 限定行循环:U 为 K,V 为 1。
|
||
localparam E2_ASLOT = 12'd1; // 存放搬迁后 e2 的 bank_a 槽位(绝不会与 t_hat 槽位冲突,K>=2)
|
||
wire [2:0] u_row_max = (st == ST_ENC_V || st == ST_DEC_W) ? 3'd1 : k_r;
|
||
// V-ADD:在 u_aidx 处读取 psum (bank_t UPSUM) + e2 (bank_a E2_ASLOT)(领先),
|
||
// 通过写入索引 u_awidx 加上 mu,将 v 写入 bank_t[UPSUM] 的 u_awidx 位置。
|
||
wire [13:0] u_v_e2rd = E2_ASLOT*256 + u_aidx[7:0]; // bank_a e2(领先)
|
||
wire [13:0] u_vadd_wr = UPSUM*256 + u_awidx; // bank_t v(写入)
|
||
wire [11:0] u_mu = m_r[u_awidx] ? 12'd1665 : 12'd0; // mu 按消息比特
|
||
wire [13:0] u_vsum = {2'b0, bt_rd_data} + {2'b0, ba_rd_data} + {2'b0, u_mu}; // psum+e2+mu
|
||
wire [13:0] u_vsub1 = (u_vsum >= 14'd3329) ? (u_vsum - 14'd3329) : u_vsum;
|
||
wire [11:0] u_vq = (u_vsub1 >= 14'd3329) ? (u_vsub1 - 14'd3329) : u_vsub1[11:0];
|
||
wire u_v_we = (st == ST_ENC_V) && (u_sub == 2'd2) && u_avalid;
|
||
|
||
// ================================================================
|
||
// D3: w = v' - INTT(sum_j s_hat[j] o u_hat[j])(Decaps ST_DEC_W)。
|
||
// 重用 u_* MAC/INTT 机(u_row 固定为 0,单个多项式):
|
||
// MAC : s_hat[j] (bank_a 槽位 j*K,== u_aslot, u_row=0) o u_hat[j]
|
||
// (bank_se 相对 j,== u_pm_b_full) -> psum bank_t[UPSUM]。(与
|
||
// Encaps V MAC 相同的寻址,后者读取 t_hat[j] o y_hat[j]。)
|
||
// INTT: INTT(psum) 原地在 bank_t[UPSUM] 中。
|
||
// SUB : w[i] = v'[i] - psum[i] mod Q。v' 在 bank_a[DEC_VASLOT](D1)中,
|
||
// psum 在 bank_t[UPSUM] 中;并行读取两者(类似于 V-ADD 读取
|
||
// psum + e2)。w 原地写回 bank_t[UPSUM]。
|
||
wire [13:0] u_w_vrd = DEC_VASLOT*256 + u_aidx[7:0]; // bank_a v'(领先)
|
||
wire [13:0] u_wsub_wr = UPSUM*256 + u_awidx; // bank_t w(写入)
|
||
wire [12:0] u_wdiff = {1'b0, ba_rd_data} - {1'b0, bt_rd_data}; // v' - psum
|
||
wire [11:0] u_wq = u_wdiff[12] ? (u_wdiff[11:0] + 12'd3329) : u_wdiff[11:0];
|
||
wire u_w_we = (st == ST_DEC_W) && (u_sub == 2'd2) && u_avalid;
|
||
|
||
// ================================================================
|
||
// D4: m' = byteEncode_1(Compress_1(w))(Decaps ST_DEC_MENC)。
|
||
// Compress_1(x) = round(2x/Q) mod 2 = 1 当且仅当 x 在 (Q/4, 3Q/4],即
|
||
// 对 Q=3329 而言 832 < x <= 2496。将 256 位 LSB-first 打包为 32 字节。
|
||
// w 从 bank_t[UPSUM] 读取(D3 的原地结果),每 2 周期 1 个系数。
|
||
reg [7:0] men_idx; // 系数 0..255
|
||
reg [1:0] men_ph; // 微相
|
||
reg men_done;
|
||
// D4 将恢复出的消息比特直接打包到 m_r 中(被 D6 的
|
||
// V/mu 重加密复用,并在 dbg_mprime_o 上暴露)。
|
||
|
||
// ================================================================
|
||
// D7: 隐式拒绝比较(Decaps ST_DEC_CMP)。
|
||
// 遍历所有 ct 字节,并行读取 c'(ct_bram)和 c(c_in_bram);
|
||
// 将每个字节差异 OR 到 cmp_neq。最后一个字节后,ss = cmp_neq
|
||
// ? K-bar : K'。遍历访问每个字节而不管早期差异
|
||
//(恒定工作量/无提前退出),匹配常量时间规范意图。
|
||
// ph0:呈现两个地址;ph1:比较寄存读取,累加。
|
||
reg [10:0] cmp_idx; // 字节索引 0..ct_bytes
|
||
reg cmp_ph; // 0=呈现地址, 1=比较
|
||
reg cmp_neq; // 粘滞:任何字节曾不同
|
||
reg cmp_done;
|
||
reg dec_reject; // 末尾锁存的 cmp_neq(驱动 ss 选择)
|
||
wire cmp_byte_neq = (ct_rd_data != cin_rd_data);
|
||
wire [13:0] men_rd = UPSUM*256 + men_idx; // bank_t w 读取地址
|
||
wire men_w_bit = (bt_rd_data > 12'd832) && (bt_rd_data <= 12'd2496); // Compress_1
|
||
|
||
// ST_ENC_E2MV:将 e2(bank_t 相对槽位 0,256 个系数)复制到 bank_a[E2_ASLOT]。
|
||
// bank_t 读取领先 (em_ridx),bank_a 写入延迟 1 周期 (em_we/em_widx)。
|
||
reg [8:0] em_ridx; // 0..256 对 e2 的预读
|
||
reg [7:0] em_widx; // bank_a 写入索引
|
||
reg em_we; // 本周起正在写入一个系数
|
||
reg em_done;
|
||
wire [13:0] em_rd = 14'd0 + em_ridx[7:0]; // bank_t 相对槽位 0 (e2)
|
||
wire [11:0] em_wa = E2_ASLOT*256 + em_widx; // bank_a E2_ASLOT
|
||
|
||
// ================================================================
|
||
// E5/E7: Compress_d + byteEncode_d -> 密文(Encaps ST_ENC_C1/C2)。
|
||
// 每个系数:读取多项式系数 -> comp_decomp(mode 0 压缩, d=du/dv)->
|
||
// 位打包器(LSB-first)-> 发射字节到 ct_bram。c1 = K 个 u 多项式
|
||
// (d=du),然后 c2 = 1 个 v 多项式 (d=dv)。每个多项式 = 256 个系数 -> 32*d
|
||
// 字节(整),因此位缓冲区在每个多项式边界处排空。
|
||
// 微相 cp_ph: 0 呈现系数地址;1 馈送 comp_decomp (cd_valid);
|
||
// 2 等待流水线;3 捕获压缩结果 + 累积比特;4..n 排空字节。
|
||
// ================================================================
|
||
wire cd_active = (st == ST_ENC_C1) || (st == ST_ENC_C2);
|
||
reg [11:0] cd_coeff; // 呈现给 comp_decomp 的系数
|
||
reg cd_valid; // 对 comp_decomp 的 1 周期脉冲
|
||
wire cd_ready;
|
||
wire [11:0] cd_out; // 压缩值(低 d 位有效)
|
||
wire cd_vo;
|
||
wire [4:0] cp_d = (st == ST_ENC_C2) ? dv_rt : du_rt; // 压缩宽度
|
||
// comp_decomp 共享:Encaps C1/C2 压缩(mode 0);Decaps DECOMP
|
||
// 解压缩(mode 1)。在 DECOMP 中解码器馈送 dec_dc_coeff/valid/d。
|
||
wire cd_dec = (st == ST_DEC_DECOMP);
|
||
wire cd_mode = cd_dec ? 1'b1 : 1'b0; // 1=解压缩
|
||
wire [4:0] cd_d_mux = cd_dec ? dec_dc_d : cp_d;
|
||
wire [11:0] cd_in_mux= cd_dec ? dec_dc_coeff : cd_coeff;
|
||
wire cd_vi_mux= cd_dec ? dec_dc_valid : cd_valid;
|
||
comp_decomp_sync u_comp (
|
||
.clk(clk), .rst_n(rst_n),
|
||
.coeff_in(cd_in_mux),
|
||
.d(cd_d_mux),
|
||
.mode(cd_mode),
|
||
.valid_i(cd_vi_mux),
|
||
.ready_o(cd_ready),
|
||
.coeff_out(cd_out),
|
||
.valid_o(cd_vo),
|
||
.ready_i(1'b1)
|
||
);
|
||
// 位打包器 / ct 遍历簿记
|
||
reg [2:0] cp_poly; // c1: 0..K-1(u 行);c2: 单个 v
|
||
reg [7:0] cp_idx; // 多项式内系数 0..255
|
||
reg [2:0] cp_ph; // 微相
|
||
reg [24:0] cp_buf; // 位累加器(LSB-first)
|
||
reg [5:0] cp_nbits; // cp_buf 中有效位数
|
||
reg [11:0] cp_wa; // ct_bram 字节写入地址(先跑 c1 再 c2)
|
||
reg cp_done; // 串行化完成(该区域)
|
||
// 系数来源:c1 (ST_ENC_C1) 读取 bank_se 相对 (K+cp_poly) 中的 u[cp_poly];
|
||
// c2 (ST_ENC_C2) 读取 bank_t 相对槽位 UPSUM 中的 v(单个多项式, cp_poly=0)。
|
||
wire [13:0] cp_se_full = ({2'b0,k_r}+{2'b0,cp_poly})*256 + cp_idx; // bank_se u[cp_poly]
|
||
wire [13:0] cp_bt_full = UPSUM*256 + cp_idx; // bank_t v (UPSUM)
|
||
// 打包器泛化(E5 c1 vs E7 c2):
|
||
// 系数来源:c1 = bank_se (u),c2 = bank_t (v)
|
||
// 多项式数量:c1 = K(u 行),c2 = 1(单个 v)
|
||
// 位宽度 cp_d 已在上面根据 C2 或 C1 声明为 dv_rt 或 du_rt。
|
||
wire [11:0] cp_coeff_src = (st == ST_ENC_C2) ? bt_rd_data : bse_rd_data;
|
||
wire [2:0] cp_poly_max = (st == ST_ENC_C2) ? 3'd1 : k_r;
|
||
|
||
// ================================================================
|
||
// D1: K-PKE byteDecode_d + 解压缩(解密 c1/c2 -> u'/v')。
|
||
// C1/C2 打包器的逆向:遍历 c_in_bram 字节,LSB-first 累积
|
||
// 到位缓冲区,提取 d 位符号,馈送 comp_decomp(mode=1
|
||
// 解压缩),并将每个结果 (mod q) 写入 bank。
|
||
// c1 = K 个多项式, d=du -> u'[i] 在 bank_se 相对 i (0..K-1) 中
|
||
// c2 = 1 个多项式, d=dv -> v' 在 bank_a 槽位 DEC_VASLOT 中(使 D3 的 w-SUB 能够
|
||
// 并行读取 psum (bank_t) 和 v' (bank_a),类似于 Encaps V-ADD)。
|
||
// 微相 dec_ph:
|
||
// 0 呈现 c_in 字节地址;1 捕获字节,追加 8 位到 buf;
|
||
// while (nbits>=d): 提取 d 位符号 -> comp_decomp(解压缩);
|
||
// 2 等待流水线;3 cd_vo -> 将系数写入 bank,推进系数索引。
|
||
// ================================================================
|
||
localparam DEC_VASLOT = 12'd1; // v' 的 bank_a 槽位(空闲: s_hat 在 j*K, 槽位 1 未用, K>=2)
|
||
reg [2:0] dec_poly; // c1: 0..K-1; c2: 单个 (=K 标记)
|
||
reg [7:0] dec_cidx; // 多项式内系数 0..255(馈送侧)
|
||
reg [7:0] dec_widx; // 多项式内系数 0..255(写回侧,延迟于流水线)
|
||
reg [1:0] dec_ph; // 微相
|
||
reg [11:0] dec_ba; // c_in_bram 字节读取地址(先 c1 后 c2)
|
||
reg [24:0] dec_buf; // 位累加器(LSB-first)
|
||
reg [5:0] dec_nbits; // dec_buf 中有效位数
|
||
reg dec_dc_done; // D1 完成(c1 和 c2 均已解码)
|
||
reg dec_in_c2; // 0 = 正在解码 c1 (u'), 1 = 正在解码 c2 (v')
|
||
// comp_decomp 馈送(解压缩):提取出的 d 位符号。
|
||
reg [11:0] dec_dc_coeff;
|
||
reg dec_dc_valid;
|
||
wire [4:0] dec_dc_d = dec_in_c2 ? dv_rt : du_rt; // c2 用 dv, c1 用 du
|
||
//(c_in_bram 读取地址由 cin_rd_addr_r 驱动,在遍历器中设为 dec_ba)
|
||
|
||
reg pm_valid;
|
||
wire pm_ready;
|
||
wire [11:0] pm_coeff;
|
||
wire pm_vo;
|
||
// pm_a: A_hat[i][j] 在 bank_a(绝对槽位 m_aslot)。pm_b: s_hat[j] 在
|
||
// bank_se(相对槽位 = m_sslot - slot_s_rt = m_j)。m_ld 是预读
|
||
// 指针;两个 bank 读取来自各自的 sd_bram(寄存,1 周期
|
||
// 延迟)并在 1 周期后馈送 poly_mul(pm_valid 延迟 1 周期)。
|
||
wire [13:0] pm_a_full = m_aslot*256 + m_ld[7:0];
|
||
wire [13:0] pm_b_full = m_j*256 + m_ld[7:0];
|
||
wire [11:0] pm_a_in = ba_rd_data; // bank_a sd_bram 寄存读取
|
||
wire [11:0] pm_b_in = bse_rd_data; // bank_se sd_bram 寄存读取(加载阶段)
|
||
|
||
poly_mul_sync u_pmul (
|
||
.clk(clk), .rst_n(rst_n),
|
||
.coeff_a_in(pm_a_in),
|
||
.coeff_b_in(pm_b_in),
|
||
.valid_i(pm_valid),
|
||
.ready_o(pm_ready),
|
||
.coeff_out(pm_coeff),
|
||
.valid_o(pm_vo),
|
||
.ready_i(1'b1)
|
||
);
|
||
|
||
// 累加器来源:首项时 (j==0) 为 e_hat[i],否则为运行的 t_hat[i]。
|
||
// e_hat[i] 在 bank_se 相对槽位 (slot_e_rt-slot_s_rt + m_i) = K+m_i。
|
||
// t_hat[i] 在 bank_t 相对槽位 m_i。两者读取均来自各自的
|
||
// sd_bram (bse_rd_data / bt_rd_data),具有相同的 1 周期延迟。
|
||
// 寄存预读:呈现下一个 pm_vo 将消耗的索引
|
||
// m_acc_radr = pm_vo ? m_oidx+1 : m_oidx
|
||
// j 选择应用于寄存输出(m_jq = (m_j==0)
|
||
// 延迟 1 周期以对齐读取延迟)。RMW 读旧值保持:读取
|
||
// 地址 (m_oidx+1) 领先写入地址 (m_oidx)。节拍 CALC/C0/C1。
|
||
wire [7:0] m_acc_radr = pm_vo ? (m_oidx + 8'd1) : m_oidx;
|
||
wire [13:0] m_eacc_full = ({2'b0, k_r} + {2'b0, m_i})*256 + m_acc_radr; // K+m_i(累加时的 bse_rd_addr)
|
||
wire [13:0] m_tacc_full = m_i*256 + m_acc_radr; // bt_rd_addr
|
||
reg m_jq; // (m_j==0) 延迟 1 周期以匹配读取延迟
|
||
// 选中的累加器来源与 pm_coeff 对齐
|
||
wire [11:0] m_acc_src = m_jq ? bse_rd_data : bt_rd_data;
|
||
// (a + b) mod Q(均 < Q,和 < 2Q):一次条件减法
|
||
wire [12:0] m_sum = {1'b0, m_acc_src} + {1'b0, pm_coeff};
|
||
wire [11:0] m_accq = (m_sum >= 13'd3329) ? (m_sum - 13'd3329) : m_sum[11:0];
|
||
|
||
always @(*) begin
|
||
st_next = st;
|
||
case (st)
|
||
ST_IDLE: if (start_i) st_next = (op_i == 2'd2) ? ST_DEC_LOAD :
|
||
(op_i == 2'd1) ? ST_ENC_H : ST_G;
|
||
// D0: dk/c 解析后稳定,然后 D1 解压缩。D1 在 u'/v'
|
||
// 计算完成后进入 DONE,使该阶段可进行 debug 检查。
|
||
ST_DEC_LOAD: st_next = ST_DEC_DECOMP;
|
||
ST_DEC_DECOMP: if (dec_dc_done) st_next = ST_DEC_SDEC;
|
||
// D2: s_hat 解码(重用 TDEC 机),然后 u_hat = NTT(u')。D2
|
||
// 在 u_hat 就绪后进入 DONE,使该阶段可进行 debug 检查。
|
||
ST_DEC_SDEC: if (td_done) st_next = ST_DEC_NTT;
|
||
ST_DEC_NTT: if (n_slot >= {2'b0, k_r}) st_next = ST_DEC_W;
|
||
// D3: w = v' - INTT(sum_j s_hat[j] o u_hat[j])。单个输出多项式
|
||
// (u_row 0..0);MAC->INTT->SUB,然后 D4 编码 m'。
|
||
ST_DEC_W: if (u_row >= 3'd1) st_next = ST_DEC_MENC;
|
||
ST_DEC_MENC: if (men_done) st_next = ST_DEC_G;
|
||
// D5: (K',r') = G(m'||h) 单块,然后 K-bar = J(z||c) 多块。
|
||
ST_DEC_G: if (sha3_vo) st_next = ST_DEC_J;
|
||
// D5 J 完成 -> D6 重加密: c' = K-PKE.Encrypt(ek_pke, m', r')。
|
||
// 重用整个 Encaps 流水线(rho 加载 -> A -> C -> ... -> C2)。
|
||
// r' 在 r_r 中(CBD 种子),m' 在 m_r 中(V/mu),ek_pke 在 ek_bram 中。
|
||
ST_DEC_J: if (dj_done) st_next = ST_ENC_LOAD;
|
||
ST_G: if (sha3_vo) st_next = ST_A;
|
||
ST_A: if (a_pair >= kk_rt) st_next = ST_C;
|
||
ST_C: if (c_poly >= {1'b0, k_r, 1'b0}) st_next = ST_N;
|
||
ST_N: if (n_slot >= {1'b0, k_r, 1'b0}) st_next = ST_M;
|
||
ST_M: if (m_i >= k_r) st_next = ST_E;
|
||
ST_E: if (e_done) st_next = ST_H;
|
||
ST_H: if (h_phase == 2'd3) st_next = ST_DONE;
|
||
// ---- Encaps ----
|
||
ST_ENC_H: if (h_phase == 2'd3) st_next = ST_ENC_G;
|
||
ST_ENC_G: if (sha3_vo) st_next = ST_ENC_LOAD; // (K,r) 已捕获
|
||
ST_ENC_LOAD: if (rl_idx >= 6'd33) st_next = ST_ENC_A; // rho 已加载
|
||
ST_ENC_A: if (a_pair >= kk_rt) st_next = ST_ENC_C;
|
||
ST_ENC_C: if (c_poly >= {k_r, 1'b1}) st_next = ST_ENC_N; // 2K+1 个多项式完成
|
||
ST_ENC_N: if (n_slot >= {2'b0, k_r}) st_next = ST_ENC_U; // K 个槽位 (y_hat)
|
||
ST_ENC_U: if (u_row >= k_r) st_next = ST_ENC_C1; // u[0..K-1] 完成
|
||
ST_ENC_C1: if (cp_done) st_next = ST_ENC_TDEC; // E5 完成 -> E6
|
||
ST_ENC_TDEC: if (td_done) st_next = ST_ENC_E2MV; // t_hat 已解码 -> 搬迁 e2
|
||
ST_ENC_E2MV: if (em_done) st_next = ST_ENC_V; // e2 已搬迁 -> 计算 v
|
||
ST_ENC_V: if (u_row >= 3'd1) st_next = ST_ENC_C2; // E6: v 完成 -> E7
|
||
ST_ENC_C2: if (cp_done) st_next = (op_r == 2'd2) ? ST_DEC_CMP : ST_DONE;
|
||
// D7: 遍历 ct 字节比较 c'(ct_bram)与 c(c_in_bram);当
|
||
// 最后一个字节比较完毕后,选择 ss = (c'==c) ? K' : K-bar 并结束。
|
||
ST_DEC_CMP: if (cmp_done) st_next = ST_DONE;
|
||
ST_DONE: st_next = ST_IDLE;
|
||
default: st_next = ST_IDLE;
|
||
endcase
|
||
end
|
||
|
||
always @(posedge clk or negedge rst_n) begin
|
||
if (!rst_n) begin
|
||
st <= ST_IDLE;
|
||
k_r <= 3'd0;
|
||
op_r <= 2'd0;
|
||
m_r <= 256'd0;
|
||
ss_r <= 256'd0;
|
||
r_r <= 256'd0;
|
||
rl_idx <= 6'd0;
|
||
rl_widx <= 6'd0;
|
||
rl_vld <= 1'b0;
|
||
td_poly <= 3'd0;
|
||
td_trip <= 8'd0;
|
||
td_ph <= 3'd0;
|
||
td_b0 <= 8'd0;
|
||
td_b1 <= 8'd0;
|
||
td_b2 <= 8'd0;
|
||
td_done <= 1'b0;
|
||
td_we <= 1'b0;
|
||
td_wa <= 12'd0;
|
||
td_wd <= 12'd0;
|
||
rho_r <= 256'd0;
|
||
sigma_r <= 256'd0;
|
||
sha3_valid <= 1'b0;
|
||
sha3_ack <= 1'b0;
|
||
snt_valid <= 1'b0;
|
||
snt_ack <= 1'b0;
|
||
a_pair <= 5'd0;
|
||
a_i <= 3'd0;
|
||
a_j <= 3'd0;
|
||
a_widx <= 8'd0;
|
||
a_busy <= 1'b0;
|
||
cbd_valid <= 1'b0;
|
||
cbd_ack <= 1'b0;
|
||
c_poly <= 3'd0;
|
||
c_widx <= 8'd0;
|
||
c_busy <= 1'b0;
|
||
n_slot <= 3'd0;
|
||
n_ridx <= 9'd0;
|
||
n_widx <= 8'd0;
|
||
n_valid <= 1'b0;
|
||
n_loading <= 1'b0;
|
||
n_pending <= 1'b0;
|
||
m_i <= 2'd0;
|
||
m_j <= 2'd0;
|
||
m_ld <= 9'd0;
|
||
m_oidx <= 8'd0;
|
||
m_loading <= 1'b0;
|
||
m_pending <= 1'b0;
|
||
pm_valid <= 1'b0;
|
||
m_jq <= 1'b0;
|
||
u_row <= 3'd0;
|
||
u_sub <= 2'd0;
|
||
u_j <= 3'd0;
|
||
u_ld <= 9'd0;
|
||
u_oidx <= 8'd0;
|
||
u_loading <= 1'b0;
|
||
u_pending <= 1'b0;
|
||
u_j0q <= 1'b0;
|
||
u_ridx <= 9'd0;
|
||
u_widx <= 8'd0;
|
||
u_nvalid <= 1'b0;
|
||
u_nloading <= 1'b0;
|
||
u_npending <= 1'b0;
|
||
u_aidx <= 9'd0;
|
||
u_awidx <= 8'd0;
|
||
u_avalid <= 1'b0;
|
||
em_ridx <= 9'd0;
|
||
em_widx <= 8'd0;
|
||
em_we <= 1'b0;
|
||
em_done <= 1'b0;
|
||
cd_coeff <= 12'd0;
|
||
cd_valid <= 1'b0;
|
||
cp_poly <= 3'd0;
|
||
cp_idx <= 8'd0;
|
||
cp_ph <= 3'd0;
|
||
cp_buf <= 25'd0;
|
||
cp_nbits <= 6'd0;
|
||
cp_wa <= 12'd0;
|
||
cp_done <= 1'b0;
|
||
ct_we <= 1'b0;
|
||
ct_wa <= 11'd0;
|
||
ct_wd <= 8'd0;
|
||
e_poly <= 3'd0;
|
||
e_pair <= 8'd0;
|
||
e_ph <= 2'd0;
|
||
e_c0_hi <= 4'd0;
|
||
e_c1_hi <= 8'd0;
|
||
e_rho <= 10'd0;
|
||
e_done <= 1'b0;
|
||
ek_we <= 1'b0;
|
||
dkp_we <= 1'b0;
|
||
ek_wa <= 11'd0;
|
||
dkp_wa <= 11'd0;
|
||
ek_wd <= 8'd0;
|
||
dkp_wd <= 8'd0;
|
||
h_block_r <= 1088'd0;
|
||
h_mbvalid <= 1'b0;
|
||
h_mblast <= 1'b0;
|
||
h_ack <= 1'b0;
|
||
hek_r <= 256'd0;
|
||
z_r <= 256'd0;
|
||
kbar_r <= 256'd0;
|
||
cin_rd_addr_r <= 11'd0;
|
||
dec_poly <= 3'd0;
|
||
dec_cidx <= 8'd0;
|
||
dec_widx <= 8'd0;
|
||
dec_ph <= 2'd0;
|
||
dec_ba <= 12'd0;
|
||
dec_buf <= 25'd0;
|
||
dec_nbits <= 6'd0;
|
||
dec_in_c2 <= 1'b0;
|
||
dec_dc_coeff <= 12'd0;
|
||
dec_dc_valid <= 1'b0;
|
||
dec_dc_done <= 1'b0;
|
||
men_idx <= 8'd0;
|
||
men_ph <= 2'd0;
|
||
men_done <= 1'b0;
|
||
cmp_idx <= 11'd0;
|
||
cmp_ph <= 1'b0;
|
||
cmp_neq <= 1'b0;
|
||
cmp_done <= 1'b0;
|
||
dec_reject <= 1'b0;
|
||
dj_blk <= 4'd0;
|
||
dj_byte <= 8'd0;
|
||
dj_phase <= 2'd0;
|
||
dj_mbvalid <= 1'b0;
|
||
dj_mblast <= 1'b0;
|
||
dj_ack <= 1'b0;
|
||
dj_done <= 1'b0;
|
||
dj_wb_vld <= 1'b0;
|
||
dj_block_r <= 1088'd0;
|
||
h_blk <= 3'd0;
|
||
h_byte <= 8'd0;
|
||
h_phase <= 2'd0;
|
||
h_wb_vld <= 1'b0;
|
||
h_wb_idx <= 8'd0;
|
||
h_wb_g <= 12'd0;
|
||
h_wb_pad <= 8'd0;
|
||
h_wb_inek <= 1'b0;
|
||
end else begin
|
||
st <= st_next;
|
||
|
||
// BRAM write-enables 默认低;写入字节时脉冲为高。
|
||
ek_we <= 1'b0;
|
||
dkp_we <= 1'b0;
|
||
td_we <= 1'b0; // TDEC bank_a 写入默认低
|
||
ct_we <= 1'b0; // ct_bram 字节写入默认低 (E5/E7)
|
||
em_we <= 1'b0; // e2 搬迁 bank_a 写入默认低 (E6)
|
||
|
||
// 从 IDLE 进入时启动:KeyGen 启动 G;Encaps 捕获
|
||
// op/m 并武装 H(ek) 机(ST_ENC_H 重用 ST_H FSM);
|
||
// Decaps 捕获 op(dk/c 已流式输入;z/h 在加载时捕获)。
|
||
if (st == ST_IDLE && start_i) begin
|
||
k_r <= k_i; // 捕获运行时 ML-KEM 参数
|
||
op_r <= op_i;
|
||
if (op_i == 2'd1) begin
|
||
m_r <= msg_i; // 捕获 Encaps 消息
|
||
// 武装 H(ek)(与 ST_E->ST_H 武装设置的字段相同)
|
||
h_blk <= 3'd0;
|
||
h_byte <= 8'd0;
|
||
h_phase <= 2'd0; // 组装
|
||
h_mbvalid<= 1'b0;
|
||
h_mblast <= 1'b0;
|
||
h_ack <= 1'b1; // 准备好消费最终摘要
|
||
h_wb_vld <= 1'b0;
|
||
end else if (op_i == 2'd2) begin
|
||
// Decaps: dk_pke/ek_pke 已在 BRAM 中;z/H(ek) 在
|
||
// 加载时捕获到 z_r/hek_r(见下方)。D0 无需其他武装。
|
||
end else begin
|
||
sha3_valid <= 1'b1;
|
||
sha3_ack <= 1'b1;
|
||
end
|
||
end
|
||
|
||
// Decaps dk 加载:将 H(ek) 和 z 字节区域捕获到寄存器中
|
||
// 随着字节流式输入(dk_pke/ek_pke 区域通过写入多路复用器进入 BRAM)。
|
||
// 区域 i 中的字节落在 [8i +: 8] 中。使用
|
||
// 实时的 k_i 边界(预加载期间 k_r 尚未捕获)。
|
||
if (dk_in_we) begin
|
||
if (dk_in_addr >= dk_ek_end_ld && dk_in_addr < dk_hek_end_ld)
|
||
hek_r[(dk_in_addr - dk_ek_end_ld)*8 +: 8] <= dk_in_byte; // H(ek)
|
||
else if (dk_in_addr >= dk_hek_end_ld)
|
||
z_r[(dk_in_addr - dk_hek_end_ld)*8 +: 8] <= dk_in_byte; // z
|
||
end
|
||
// valid 被接受后撤销
|
||
if (sha3_valid && sha3_ready) sha3_valid <= 1'b0;
|
||
|
||
// G 完成时捕获 rho/sigma;武装 A 阶段
|
||
if (st == ST_G && sha3_vo) begin
|
||
rho_r <= sha3_hash[255:0]; // rho = G 输出字节 0..31
|
||
sigma_r <= sha3_hash[511:256]; // sigma = 字节 32..63
|
||
sha3_ack <= 1'b0;
|
||
snt_valid <= 1'b1; // 启动第一个 SampleNTT
|
||
snt_ack <= 1'b1;
|
||
a_pair <= 5'd0;
|
||
a_i <= 3'd0;
|
||
a_j <= 3'd0;
|
||
a_widx <= 8'd0;
|
||
a_busy <= 1'b0;
|
||
end
|
||
|
||
// ---- ST_A / ST_ENC_A: 驱动 SampleNTT, 每对存储 256 个系数 ----
|
||
if (st == ST_A || st == ST_ENC_A) begin
|
||
// 该对的请求被接受后标记忙碌
|
||
if (snt_valid && snt_ready) begin
|
||
snt_valid <= 1'b0;
|
||
a_busy <= 1'b1;
|
||
end
|
||
|
||
// 仅在忙碌时存储每个输出系数(忽略前一个多项式的
|
||
// 过期尾系数)。bank_a 写入本身由上面的组合逻辑
|
||
// ba_we/ba_wa/ba_wd assign 完成;这里我们只推进
|
||
// 写入索引和 (i,j) 簿记。
|
||
if (a_busy && snt_vo && snt_ack) begin
|
||
if (snt_last) begin
|
||
// 完成此多项式;按行主序推进 (i,j)
|
||
a_pair <= a_pair + 5'd1;
|
||
a_widx <= 8'd0;
|
||
a_busy <= 1'b0;
|
||
if (a_j + 3'd1 < k_r) begin
|
||
a_j <= a_j + 3'd1;
|
||
end else begin
|
||
a_j <= 3'd0;
|
||
a_i <= a_i + 3'd1;
|
||
end
|
||
// 如果还有更多对,启动下一个 SampleNTT
|
||
if (a_pair + 5'd1 < kk_rt) snt_valid <= 1'b1;
|
||
end else begin
|
||
a_widx <= a_widx + 8'd1;
|
||
end
|
||
end
|
||
end
|
||
|
||
// A 完成时武装 C 阶段(KeyGen ST_A 或 Encaps ST_ENC_A)
|
||
if ((st == ST_A && st_next == ST_C) ||
|
||
(st == ST_ENC_A && st_next == ST_ENC_C)) begin
|
||
cbd_valid <= 1'b1;
|
||
cbd_ack <= 1'b1;
|
||
c_poly <= 3'd0;
|
||
c_widx <= 8'd0;
|
||
c_busy <= 1'b0;
|
||
end
|
||
|
||
// ---- ST_C / ST_ENC_C: 驱动 CBD, 每个多项式存储 256 个 mod-q 系数 ----
|
||
// KeyGen: 2K 个多项式 (s,e)。Encaps: 2K+1 个多项式 (y,e1,e2)。循环边界
|
||
// 不同:KeyGen 在 c_poly+1 < 2K 时重启;Encaps 在 < 2K+1 时重启。
|
||
if (st == ST_C || st == ST_ENC_C) begin
|
||
if (cbd_valid && cbd_ready) begin
|
||
cbd_valid <= 1'b0;
|
||
c_busy <= 1'b1;
|
||
end
|
||
|
||
if (c_busy && cbd_vo && cbd_ack) begin
|
||
if (cbd_last) begin
|
||
c_poly <= c_poly + 3'd1;
|
||
c_widx <= 8'd0;
|
||
c_busy <= 1'b0;
|
||
// 当还有更多多项式时重启下一个(状态相关边界)
|
||
if (st == ST_ENC_C) begin
|
||
if (c_poly + 3'd1 < {k_r, 1'b1}) cbd_valid <= 1'b1; // < 2K+1
|
||
end else begin
|
||
if (c_poly + 3'd1 < {1'b0, k_r, 1'b0}) cbd_valid <= 1'b1; // < 2K
|
||
end
|
||
end else begin
|
||
c_widx <= c_widx + 8'd1;
|
||
end
|
||
end
|
||
end
|
||
|
||
// C 完成时武装 N 阶段:启动槽位 S0 的加载。n_ridx 是
|
||
// 预读指针;bank_se 读取在 sd_bram 内寄存 (bse_rd_data)
|
||
// 并在 1 周期后馈送 ntt_core,因此 valid 从低开始(启动)。
|
||
if ((st == ST_C && st_next == ST_N) ||
|
||
(st == ST_ENC_C && st_next == ST_ENC_N) ||
|
||
(st == ST_DEC_SDEC && st_next == ST_DEC_NTT)) begin
|
||
n_slot <= 3'd0;
|
||
n_ridx <= 9'd0;
|
||
n_widx <= 8'd0;
|
||
n_valid <= 1'b0;
|
||
n_loading <= 1'b1; // 开始呈现加载地址
|
||
n_pending <= 1'b0;
|
||
end
|
||
|
||
// ---- ST_N / ST_ENC_N / ST_DEC_NTT: 原地前向 NTT。KeyGen: 2K
|
||
// 槽位 (s,e)。Encaps: K 槽位 (y)。Decaps D2: K 槽位 (u' -> u_hat)。----
|
||
if (st == ST_N || st == ST_ENC_N || st == ST_DEC_NTT) begin
|
||
// 槽位计数边界:KeyGen 为 2K,Encaps 为 K
|
||
//(见下面 n_slot_max);两种方式的 LOAD/OUTPUT 节拍相同。
|
||
if (n_loading) begin
|
||
if (n_ridx == 9'd256) begin
|
||
// 本周起已消耗第 256 个系数;停止呈现地址
|
||
n_loading <= 1'b0;
|
||
n_valid <= 1'b0;
|
||
end else begin
|
||
n_ridx <= n_ridx + 9'd1;
|
||
n_valid <= 1'b1; // 上一周期呈现的数据有效
|
||
end
|
||
end
|
||
|
||
// OUTPUT 阶段:收集 256 个结果,写回相同槽位。
|
||
if (ntt_vo) begin
|
||
n_widx <= n_widx + 8'd1; // 最后之后 255->0 回绕
|
||
end
|
||
|
||
// 当 ntt_core 返回 DONE 时槽位完成
|
||
if (ntt_done) begin
|
||
if (n_slot + 3'd1 < n_slot_max) begin
|
||
n_slot <= n_slot + 3'd1;
|
||
n_widx <= 8'd0;
|
||
n_pending <= 1'b1; // 等待一个周期让 core 进入 IDLE
|
||
end else begin
|
||
n_slot <= n_slot + 3'd1; // == n_slot_max -> 退出
|
||
end
|
||
end
|
||
|
||
// core 回到 IDLE 后启动下一个槽位的加载(重新启动)
|
||
if (n_pending && ntt_ready && !ntt_done) begin
|
||
n_ridx <= 9'd0;
|
||
n_valid <= 1'b0;
|
||
n_loading <= 1'b1;
|
||
n_pending <= 1'b0;
|
||
end
|
||
end
|
||
|
||
// N 完成时武装 M 阶段:启动首对 (i=0,j=0) poly_mul 加载。
|
||
// m_ld 预读指针;bank_a/bank_se sd_bram 读取在 1 周期后
|
||
// 到达,pm_valid 在地址呈现一周期后断言。
|
||
if (st == ST_N && st_next == ST_M) begin
|
||
m_i <= 2'd0;
|
||
m_j <= 2'd0;
|
||
m_ld <= 9'd0;
|
||
m_oidx <= 8'd0;
|
||
m_loading <= 1'b1;
|
||
m_pending <= 1'b0;
|
||
pm_valid <= 1'b0;
|
||
end
|
||
|
||
// ---- ST_M: t_hat[i] = e_hat[i] + sum_j A[i][j] o s_hat[j] ----
|
||
if (st == ST_M) begin
|
||
// 累加器读取来自 sd_bram(bse_rd_data e_hat /
|
||
// bt_rd_data t_hat)。m_jq 将 j 选择与 1 周期
|
||
// 读取延迟对齐。(bse_rd_addr 通过 m_loading 在加载和累加之间多路复用。)
|
||
m_jq <= (m_j == 2'd0);
|
||
|
||
// LOAD:通过 sd_bram 读取端口(m_loading 期间
|
||
// ba_rd_addr=pm_a_full, bse_rd_addr=pm_b_full)向 bank_a/bank_se 呈现预读地址;
|
||
// ba_rd_data/bse_rd_data 在下一个周期到达并
|
||
// 由 poly_mul (pm_valid) 消耗。poly_mul 在整个 LOAD 期间保持 ready 高电平,
|
||
// 因此固定的 1 周期偏移足够。
|
||
if (m_loading) begin
|
||
if (m_ld == 9'd256) begin
|
||
pm_valid <= 1'b0; // 本周起已消耗第 256 对
|
||
m_loading <= 1'b0;
|
||
m_ld <= 9'd0;
|
||
m_oidx <= 8'd0;
|
||
end else begin
|
||
m_ld <= m_ld + 9'd1;
|
||
pm_valid <= 1'b1; // 上一周期呈现的系数对有效
|
||
end
|
||
end
|
||
|
||
// ACCUMULATE: 每个乘积系数 += e_hat (j==0) 或运行的 t_hat。
|
||
// bank_t 写入由下方的组合逻辑 bt_we/bt_wa/bt_wd assign 完成;
|
||
// 这里我们只推进累加索引 / (i,j)。
|
||
if (pm_vo) begin
|
||
if (m_oidx == 8'd255) begin
|
||
// 完成此 (i,j) 项;推进
|
||
if (m_j + 2'd1 < k_r) begin
|
||
m_j <= m_j + 2'd1;
|
||
m_pending <= 1'b1; // 下一个项,同一行
|
||
end else begin
|
||
m_j <= 2'd0;
|
||
m_i <= m_i + 2'd1; // 下一行(或 == K -> DONE)
|
||
if (m_i + 2'd1 < k_r) m_pending <= 1'b1;
|
||
end
|
||
end else begin
|
||
m_oidx <= m_oidx + 8'd1;
|
||
end
|
||
end
|
||
|
||
// core 再次进入 IDLE 后启动下一个 (i,j) poly_mul 加载(重新启动)
|
||
if (m_pending && pm_ready && !pm_vo) begin
|
||
m_loading <= 1'b1;
|
||
m_ld <= 9'd0;
|
||
m_oidx <= 8'd0;
|
||
pm_valid <= 1'b0;
|
||
m_pending <= 1'b0;
|
||
end
|
||
end
|
||
|
||
// N 完成时武装 Encaps U 阶段:启动首行 MAC (i=0,j=0)。
|
||
if (st == ST_ENC_N && st_next == ST_ENC_U) begin
|
||
u_row <= 3'd0;
|
||
u_sub <= 2'd0; // MAC
|
||
u_j <= 3'd0;
|
||
u_ld <= 9'd0;
|
||
u_oidx <= 8'd0;
|
||
u_loading <= 1'b1;
|
||
u_pending <= 1'b0;
|
||
pm_valid <= 1'b0;
|
||
end
|
||
|
||
// ---- ST_ENC_U/V 子阶段 0: MAC sum_j (A^T 或 t_hat)[j] o y_hat[j] ----
|
||
// psum(j==0 时初始化为 0)累加到 bank_t[UPSUM]。镜像 ST_M
|
||
// 加载/累加节拍(预读 1,通过 u_j0q 进行 j 选择)。
|
||
// U: A^T[u_row][j] (bank_a u_j*K+u_row)。V: t_hat[j] (bank_a u_j*K, u_row=0)。
|
||
if ((st == ST_ENC_U || st == ST_ENC_V || st == ST_DEC_W) && u_sub == 2'd0) begin
|
||
u_j0q <= (u_j == 3'd0);
|
||
|
||
if (u_loading) begin
|
||
if (u_ld == 9'd256) begin
|
||
pm_valid <= 1'b0;
|
||
u_loading <= 1'b0;
|
||
u_ld <= 9'd0;
|
||
u_oidx <= 8'd0;
|
||
end else begin
|
||
u_ld <= u_ld + 9'd1;
|
||
pm_valid <= 1'b1;
|
||
end
|
||
end
|
||
|
||
if (pm_vo) begin
|
||
// bank_t psum 写入是组合逻辑的 (u_psum_we);推进索引
|
||
if (u_oidx == 8'd255) begin
|
||
if (u_j + 3'd1 < k_r) begin
|
||
u_j <= u_j + 3'd1;
|
||
u_pending <= 1'b1; // 下一个项,同一行
|
||
end else begin
|
||
// 行的 MAC 完成 -> INTT 子阶段
|
||
u_sub <= 2'd1;
|
||
u_ridx <= 9'd0;
|
||
u_widx <= 8'd0;
|
||
u_nvalid <= 1'b0;
|
||
u_nloading <= 1'b1;
|
||
end
|
||
end else begin
|
||
u_oidx <= u_oidx + 8'd1;
|
||
end
|
||
end
|
||
|
||
// 重新启动下一个项的 poly_mul 加载
|
||
if (u_pending && pm_ready && !pm_vo) begin
|
||
u_loading <= 1'b1;
|
||
u_ld <= 9'd0;
|
||
u_oidx <= 8'd0;
|
||
pm_valid <= 1'b0;
|
||
u_pending <= 1'b0;
|
||
end
|
||
end
|
||
|
||
// ---- ST_ENC_U/V 子阶段 1: INTT(psum) mode=1 原地(bank_t)----
|
||
if ((st == ST_ENC_U || st == ST_ENC_V || st == ST_DEC_W) && u_sub == 2'd1) begin
|
||
if (u_nloading) begin
|
||
if (u_ridx == 9'd256) begin
|
||
u_nloading <= 1'b0;
|
||
u_nvalid <= 1'b0;
|
||
end else begin
|
||
u_ridx <= u_ridx + 9'd1;
|
||
u_nvalid <= 1'b1;
|
||
end
|
||
end
|
||
if (ntt_vo) u_widx <= u_widx + 8'd1; // 原地写入 (u_intt_we)
|
||
if (ntt_done) begin
|
||
// INTT 完成 -> ADD 子阶段(psum + e1[u_row])
|
||
u_sub <= 2'd2;
|
||
u_aidx <= 9'd0;
|
||
u_awidx <= 8'd0;
|
||
u_avalid <= 1'b0;
|
||
end
|
||
end
|
||
|
||
// ---- ST_ENC_U/V + ST_DEC_W 子阶段 2: ADD/SUB + 写回 ----
|
||
// U: u[u_row] = psum + e1[u_row] mod Q -> bank_se (u_add_we)。
|
||
// V: v = psum + e2 + mu mod Q -> bank_t[UPSUM] (u_v_we)。
|
||
// D3 w = v' - psum mod Q -> bank_t[UPSUM] (u_w_we)。
|
||
// 在 u_aidx 处读取 psum (bank_t) + e1/e2/v';两者在 1 周期后到达,因此
|
||
// 寄存器 (valid,widx) 并在下一个周期写入。u_row_max 限定
|
||
// 行循环(U 为 K,V/D3 为 1)。
|
||
if ((st == ST_ENC_U || st == ST_ENC_V || st == ST_DEC_W) && u_sub == 2'd2) begin
|
||
if (u_aidx < 9'd256) begin
|
||
u_aidx <= u_aidx + 9'd1;
|
||
u_avalid <= 1'b1; // 本周起地址已呈现 -> 下周起写入
|
||
u_awidx <= u_aidx[7:0];
|
||
end else begin
|
||
u_avalid <= 1'b0; // 没有更多地址
|
||
end
|
||
// 写回(u_add_we / u_v_we)在本周期提交索引 u_awidx。
|
||
// 在第 256 个系数 (u_awidx==255) 被写后推进行。
|
||
if (u_avalid && u_awidx == 8'd255) begin
|
||
if (u_row + 3'd1 < u_row_max) begin
|
||
u_row <= u_row + 3'd1;
|
||
u_sub <= 2'd0; // 下一行 MAC
|
||
u_j <= 3'd0;
|
||
u_ld <= 9'd0;
|
||
u_oidx <= 8'd0;
|
||
u_loading <= 1'b1;
|
||
u_pending <= 1'b0;
|
||
pm_valid <= 1'b0;
|
||
end else begin
|
||
u_row <= u_row + 3'd1; // U: ==K ->C1; V: ==1 ->DONE
|
||
end
|
||
end
|
||
end
|
||
|
||
// U 完成时武装 E5 (ST_ENC_C1):c1 = byteEncode_du(Compress_du(u))。
|
||
// 遍历 K 个多项式 * 256 个系数;复位位打包器 + ct 写入指针。
|
||
if (st == ST_ENC_U && st_next == ST_ENC_C1) begin
|
||
cp_poly <= 3'd0;
|
||
cp_idx <= 8'd0;
|
||
cp_ph <= 3'd0;
|
||
cp_buf <= 25'd0;
|
||
cp_nbits <= 6'd0;
|
||
cp_wa <= 12'd0;
|
||
cp_done <= 1'b0;
|
||
cd_valid <= 1'b0;
|
||
end
|
||
|
||
// ---- ST_ENC_C1/C2: Compress_d -> byteEncode_d -> ct 区域 ----
|
||
// C1 (E5): Compress_du(u[0..K-1]) 从 bank_se -> ct[0..c1_bytes)。
|
||
// C2 (E7): Compress_dv(v) 从 bank_t[UPSUM] -> ct[c1_bytes..ct_bytes)。
|
||
// 每个系数,5 阶段微序列(预读 1 周期 bram + 1 周期
|
||
// comp_decomp 流水线),然后排空子阶段发射整字节:
|
||
// ph0: 呈现系数地址(按状态 cp_se_full / cp_bt_full)。
|
||
// ph1: 系数到达 (cp_coeff_src) -> 锁存到 cd_coeff,脉冲 cd_valid。
|
||
// ph2: 撤销 cd_valid(1 周期脉冲);comp_decomp 捕获。
|
||
// ph3: cd_vo 高 -> cd_out(低 cp_d 位)有效;LSB-first 追加。
|
||
// ph4: 排空: 当缓冲 >=8 位时,每周期发射一个 ct 字节;然后推进。
|
||
// 每个多项式 = 256 个系数 = 32*d 字节(整),因此 cp_buf 在每个
|
||
// 多项式边界排空(跨多项式/区域无进位)。
|
||
if ((st == ST_ENC_C1 || st == ST_ENC_C2) && !cp_done) begin
|
||
case (cp_ph)
|
||
3'd0: cp_ph <= 3'd1; // 地址已呈现;等待读取
|
||
3'd1: begin
|
||
cd_coeff <= cp_coeff_src; // u (bank_se) 或 v (bank_t)
|
||
cd_valid <= 1'b1; // 馈送 comp_decomp(1 周期脉冲)
|
||
cp_ph <= 3'd2;
|
||
end
|
||
3'd2: begin
|
||
cd_valid <= 1'b0; // 本周起 comp_decomp 已捕获
|
||
cp_ph <= 3'd3;
|
||
end
|
||
3'd3: begin
|
||
// cd_out 有效 (cd_vo): LSB-first 在位 cp_nbits 处追加 cp_d 位
|
||
cp_buf <= cp_buf | (({13'd0, cd_out} & ((25'd1 << cp_d) - 25'd1)) << cp_nbits);
|
||
cp_nbits <= cp_nbits + {1'b0, cp_d};
|
||
cp_ph <= 3'd4;
|
||
end
|
||
default: begin // 3'd4: 排空整字节
|
||
if (cp_nbits >= 6'd8) begin
|
||
ct_we <= 1'b1;
|
||
ct_wa <= cp_wa;
|
||
ct_wd <= cp_buf[7:0];
|
||
cp_wa <= cp_wa + 12'd1;
|
||
cp_buf <= cp_buf >> 8;
|
||
cp_nbits <= cp_nbits - 6'd8;
|
||
end else begin
|
||
// 系数完全打包;推进系数 / 多项式
|
||
if (cp_idx == 8'd255) begin
|
||
cp_idx <= 8'd0;
|
||
if (cp_poly + 3'd1 < cp_poly_max) cp_poly <= cp_poly + 3'd1;
|
||
else cp_done <= 1'b1; // 区域完成
|
||
end else begin
|
||
cp_idx <= cp_idx + 8'd1;
|
||
end
|
||
cp_ph <= 3'd0;
|
||
end
|
||
end
|
||
endcase
|
||
end
|
||
|
||
// V 完成时武装 E7 (ST_ENC_C2):c2 = byteEncode_dv(Compress_dv(v))。
|
||
// 单个多项式(v 在 bank_t UPSUM);ct 写入指针 cp_wa 从 c1_bytes
|
||
// 继续(不重置),因此 c2 紧跟 c1 之后。cp_buf/nbits
|
||
// 此处为 0(c1 结束时在多项式/字节边界上),但为安全复位。
|
||
if (st == ST_ENC_V && st_next == ST_ENC_C2) begin
|
||
cp_poly <= 3'd0;
|
||
cp_idx <= 8'd0;
|
||
cp_ph <= 3'd0;
|
||
cp_buf <= 25'd0;
|
||
cp_nbits <= 6'd0;
|
||
cp_done <= 1'b0;
|
||
cd_valid <= 1'b0;
|
||
// cp_wa 有意保留(= 来自 C1 的 c1_bytes_rt)。
|
||
end
|
||
|
||
// 加载稳定后武装 D1 DECOMP:先解码 c1 (u')。
|
||
if (st == ST_DEC_LOAD && st_next == ST_DEC_DECOMP) begin
|
||
dec_poly <= 3'd0;
|
||
dec_cidx <= 8'd0;
|
||
dec_widx <= 8'd0;
|
||
dec_ph <= 2'd0;
|
||
dec_ba <= 12'd0;
|
||
dec_buf <= 25'd0;
|
||
dec_nbits <= 6'd0;
|
||
dec_in_c2 <= 1'b0;
|
||
dec_dc_valid <= 1'b0;
|
||
dec_dc_done <= 1'b0;
|
||
cin_rd_addr_r<= 11'd0; // 呈现字节 0 地址
|
||
end
|
||
|
||
// ---- ST_DEC_DECOMP (D1): byteDecode_d + 解压缩 c1/c2 ----
|
||
// C1/C2 打包器的逆向。每个系数:
|
||
// ph0: 若 nbits<d,需要一个字节(地址已呈现)-> ph1;
|
||
// 否则提取低 d 位 -> comp_decomp(解压缩)-> ph2。
|
||
// ph1: 在 dec_nbits 处追加 cin_rd_data(8 位);推进 dec_ba;
|
||
// 呈现下一个字节地址;回到 ph0。
|
||
// ph2: 撤销 dc_valid(脉冲已捕获)-> ph3。
|
||
// ph3: cd_vo -> dec_u_we/dec_v_we 写入 cd_out;推进系数。
|
||
// c1 = K 个多项式 (d=du) -> u'[poly] bank_se;然后 c2 = 1 个多项式 (d=dv)
|
||
// -> v' bank_a[DEC_VASLOT]。字节流在 c_in_bram 中连续。
|
||
if (st == ST_DEC_DECOMP && !dec_dc_done) begin
|
||
case (dec_ph)
|
||
2'd0: begin
|
||
if (dec_nbits >= {1'b0, dec_dc_d}) begin
|
||
// 足够位数:提取低 d 位作为解码符号
|
||
dec_dc_coeff <= dec_buf[11:0] & ((12'd1 << dec_dc_d) - 12'd1);
|
||
dec_dc_valid <= 1'b1;
|
||
dec_buf <= dec_buf >> dec_dc_d;
|
||
dec_nbits <= dec_nbits - {1'b0, dec_dc_d};
|
||
dec_ph <= 2'd2;
|
||
end else begin
|
||
// 需要另一个字节(cin_rd_data 反映 dec_ba)
|
||
dec_ph <= 2'd1;
|
||
end
|
||
end
|
||
2'd1: begin
|
||
dec_buf <= dec_buf | ({17'd0, cin_rd_data} << dec_nbits);
|
||
dec_nbits <= dec_nbits + 6'd8;
|
||
dec_ba <= dec_ba + 12'd1;
|
||
cin_rd_addr_r<= dec_ba[10:0] + 11'd1; // 呈现下一个字节
|
||
dec_ph <= 2'd0;
|
||
end
|
||
2'd2: begin
|
||
dec_dc_valid <= 1'b0; // comp_decomp 已捕获
|
||
dec_ph <= 2'd3;
|
||
end
|
||
default: begin // 2'd3: 捕获 cd_vo
|
||
if (cd_vo) begin
|
||
// 本周起 dec_u_we/dec_v_we 在 dec_widx 处提交 cd_out。
|
||
dec_widx <= dec_widx + 8'd1;
|
||
if (dec_cidx == 8'd255) begin
|
||
dec_cidx <= 8'd0;
|
||
dec_widx <= 8'd0;
|
||
if (!dec_in_c2) begin
|
||
if (dec_poly + 3'd1 < k_r) begin
|
||
dec_poly <= dec_poly + 3'd1; // 下一行 u'
|
||
end else begin
|
||
dec_in_c2 <= 1'b1; // 切换到 c2 (v')
|
||
dec_poly <= 3'd0;
|
||
end
|
||
end else begin
|
||
dec_dc_done <= 1'b1; // v' 完成 -> D1 完成
|
||
end
|
||
end else begin
|
||
dec_cidx <= dec_cidx + 8'd1;
|
||
end
|
||
dec_ph <= 2'd0;
|
||
end
|
||
end
|
||
endcase
|
||
end
|
||
|
||
// M 完成时武装 E 阶段
|
||
if (st == ST_M && st_next == ST_E) begin
|
||
e_poly <= 3'd0;
|
||
e_pair <= 8'd0;
|
||
e_ph <= 2'd0; // 从第一对系数的取回-c0 开始
|
||
e_rho <= 10'd0;
|
||
e_done <= 1'b0;
|
||
end
|
||
|
||
// ---- ST_E: byteEncode12 t_hat -> ek, s_hat -> dk_pke ----
|
||
// 每个系数对单周期寄存 bank 读取;4 周期微相(ph0 取回 c0,
|
||
// ph1 写入 b0 + 取回 c1, ph2 写入 b1,
|
||
// ph3 写入 b2)。上一周期呈现地址对应的系数是
|
||
// e_rd_coeff(dk 半部分为 bse_rd_data,ek 半部分为 bt_rd_data),
|
||
// 两者在各自的 sd_bram 内寄存(ST_E 中 bse_rd_addr/bt_rd_addr = e_rd_full)。
|
||
if (st == ST_E && !e_done) begin
|
||
if (e_poly < {1'b0, k_r, 1'b0}) begin
|
||
// ph0: 仅取回(启动)。ph1..3: 写入一个打包字节。
|
||
if (e_ph != 2'd0) begin
|
||
if (!e_is_dk) begin
|
||
ek_we <= 1'b1;
|
||
ek_wa <= e_boff[10:0] + {9'd0, e_wb};
|
||
ek_wd <= e_wbyte;
|
||
end else begin
|
||
dkp_we <= 1'b1;
|
||
dkp_wa <= e_boff[10:0] + {9'd0, e_wb};
|
||
dkp_wd <= e_wbyte;
|
||
end
|
||
end
|
||
// 系数高半字节可用时保存
|
||
if (e_ph == 2'd1) e_c0_hi <= e_rd_coeff[11:8]; // c0[11:8]
|
||
if (e_ph == 2'd2) e_c1_hi <= e_rd_coeff[11:4]; // c1[11:4]
|
||
|
||
// 推进微相 / 系数对 / 多项式
|
||
if (e_ph == 2'd3) begin
|
||
e_ph <= 2'd0;
|
||
if (e_pair == 8'd127) begin
|
||
e_pair <= 8'd0;
|
||
e_poly <= e_poly + 5'd1; // 下一个多项式 或 -> rho 阶段
|
||
end else begin
|
||
e_pair <= e_pair + 8'd1;
|
||
end
|
||
end else begin
|
||
e_ph <= e_ph + 2'd1;
|
||
end
|
||
end else begin
|
||
// rho 复制:ek[384*K + r] = rho 字节 r(r = 0..31),1 字节/周期
|
||
ek_we <= 1'b1;
|
||
ek_wa <= dk_bytes_rt[10:0] + {1'b0, e_rho};
|
||
ek_wd <= rho_r[e_rho*8 +: 8];
|
||
if (e_rho == 10'd31) e_done <= 1'b1;
|
||
else e_rho <= e_rho + 10'd1;
|
||
end
|
||
end
|
||
|
||
// E 完成时武装 H 阶段
|
||
if (st == ST_E && st_next == ST_H) begin
|
||
h_blk <= 3'd0;
|
||
h_byte <= 8'd0;
|
||
h_phase <= 2'd0; // 组装
|
||
h_mbvalid<= 1'b0;
|
||
h_mblast <= 1'b0;
|
||
h_ack <= 1'b1; // 准备好消费最终摘要
|
||
h_wb_vld <= 1'b0; // 没有待处理的写回
|
||
end
|
||
|
||
// ---- ST_H / ST_ENC_H: 通过多块 SHA3-256 计算 H(ek) ----
|
||
// KeyGen(ek 刚由 ST_E 写入)和 Encaps(ek
|
||
// 由 TB 预加载到 ek_bram)使用相同逻辑。hek_r 捕获 H(ek)。
|
||
if (st == ST_H || st == ST_ENC_H) begin
|
||
case (h_phase)
|
||
// 将块 h_blk 的 136 个字节组装到 h_block_r 中。
|
||
// ek BRAM 读取是寄存的:本周起呈现 h_byte 的地址,
|
||
// 将上一周期呈现地址对应的到达字节写回(h_wb_*)。
|
||
// h_byte 运行 0..136(额外一个周期以刷新最终写回)。
|
||
2'd0: begin
|
||
// 写回上一地址读取的字节
|
||
if (h_wb_vld)
|
||
h_block_r[h_wb_idx*8 +: 8] <= h_wb_inek ? ek_rd_data : h_wb_pad;
|
||
|
||
if (h_byte <= 8'd135) begin
|
||
// 为本周起呈现的地址设置写回
|
||
h_wb_vld <= 1'b1;
|
||
h_wb_idx <= h_byte;
|
||
h_wb_g <= h_g_addr;
|
||
h_wb_inek <= (h_g_addr < ek_bytes_rt);
|
||
h_wb_pad <= h_padconst(h_blk, h_byte);
|
||
h_byte <= h_byte + 8'd1;
|
||
end else begin
|
||
// h_byte==136: 最终写回(字节 135)已在上方完成
|
||
h_wb_vld <= 1'b0;
|
||
h_byte <= 8'd0;
|
||
h_mbvalid <= 1'b1;
|
||
h_mblast <= (h_blk == h_nblk_rt - 4'd1);
|
||
h_phase <= 2'd1; // 馈送
|
||
end
|
||
end
|
||
// 馈送: 保持 valid 直到被接受(mb_ready 撤销)
|
||
2'd1: begin
|
||
if (h_mbvalid && !h_mbready) begin
|
||
h_mbvalid <= 1'b0;
|
||
h_mblast <= 1'b0;
|
||
h_phase <= 2'd2; // 等待置换
|
||
end
|
||
end
|
||
// 等待置换完成:再次就绪(更多块)或摘要有效(最后一块)
|
||
2'd2: begin
|
||
if (h_vo) begin
|
||
hek_r <= h_hash[255:0];
|
||
h_phase <= 2'd3; // 完成
|
||
end else if (h_mbready) begin
|
||
h_blk <= h_blk + 3'd1;
|
||
h_phase <= 2'd0; // 组装下一个块
|
||
end
|
||
end
|
||
default: ; // 2'd3 完成: 保持
|
||
endcase
|
||
end
|
||
|
||
// H(ek) 完成时武装 Encaps G:触发 64 字节单块
|
||
// G(m||H(ek))。hek_r 现在保存 H(ek);enc_g_data = {hek_r, m_r}。
|
||
if (st == ST_ENC_H && st_next == ST_ENC_G) begin
|
||
sha3_valid <= 1'b1;
|
||
sha3_ack <= 1'b1;
|
||
end
|
||
// Encaps G 完成时捕获 (K, r)。ss = K = 低半部分,r = 高半部分。
|
||
if (st == ST_ENC_G && sha3_vo) begin
|
||
ss_r <= sha3_hash[255:0]; // K(共享密钥)= G 字节 0..31
|
||
r_r <= sha3_hash[511:256]; // r = G 字节 32..63
|
||
sha3_ack <= 1'b0;
|
||
end
|
||
|
||
// m' 就绪时武装 Decaps D5 G(ST_DEC_MENC -> ST_DEC_G):触发
|
||
// 64 字节单块 G(m'||h)。dec_g_data = {hek_r, m_r}。
|
||
if (st == ST_DEC_MENC && st_next == ST_DEC_G) begin
|
||
sha3_valid <= 1'b1;
|
||
sha3_ack <= 1'b1;
|
||
end
|
||
// D5 G 完成时捕获 (K', r')。K' = 低半部分(候选 ss),
|
||
// r' = 高半部分(D6 重加密的 PRF 种子)。重用 ss_r / r_r。
|
||
if (st == ST_DEC_G && sha3_vo) begin
|
||
ss_r <= sha3_hash[255:0]; // K' = G 字节 0..31
|
||
r_r <= sha3_hash[511:256]; // r' = G 字节 32..63
|
||
sha3_ack <= 1'b0;
|
||
end
|
||
|
||
// G 完成时武装 D5 J(z||c)(ST_DEC_G -> ST_DEC_J):组装
|
||
// 第一个 136 字节块。dj_ack 高电平以消费最终摘要。
|
||
if (st == ST_DEC_G && st_next == ST_DEC_J) begin
|
||
dj_blk <= 4'd0;
|
||
dj_byte <= 8'd0;
|
||
dj_phase <= 2'd0;
|
||
dj_mbvalid<= 1'b0;
|
||
dj_mblast <= 1'b0;
|
||
dj_ack <= 1'b1;
|
||
dj_done <= 1'b0;
|
||
dj_wb_vld <= 1'b0;
|
||
cin_rd_addr_r <= 11'd0; // 呈现 c 字节 0(g=32 -> c_idx 0)
|
||
end
|
||
|
||
// ---- ST_DEC_J: K-bar = J(z||c) 多块 SHAKE256 ----
|
||
// 镜像 H(ek) 多块机。按全局 g 的字节来源:
|
||
// g < 32 -> z_r 字节 g
|
||
// 32 <= g < msglen -> c_in_bram 字节 (g-32),寄存读取
|
||
// 否则 -> SHAKE256 填充常量
|
||
// c_in_bram 读取是寄存的:本周起呈现 dj_byte 的 c_idx,
|
||
// 将上一周期呈现地址对应的到达字节写回。
|
||
if (st == ST_DEC_J && !dj_done) begin
|
||
case (dj_phase)
|
||
2'd0: begin
|
||
// 写回上一地址读取的字节
|
||
if (dj_wb_vld) begin
|
||
if (dj_wb_inz)
|
||
dj_block_r[dj_wb_idx*8 +: 8] <= z_r[dj_wb_zidx*8 +: 8];
|
||
else if (dj_wb_inc)
|
||
dj_block_r[dj_wb_idx*8 +: 8] <= cin_rd_data;
|
||
else
|
||
dj_block_r[dj_wb_idx*8 +: 8] <= dj_wb_pad;
|
||
end
|
||
if (dj_byte <= 8'd135) begin
|
||
dj_wb_vld <= 1'b1;
|
||
dj_wb_idx <= dj_byte;
|
||
dj_wb_inz <= (dj_g < 12'd32);
|
||
dj_wb_inc <= (dj_g >= 12'd32) && (dj_g < dj_msglen);
|
||
dj_wb_zidx <= dj_g[4:0];
|
||
dj_wb_pad <= dj_padconst(dj_g);
|
||
// c_in 地址以组合逻辑方式呈现(ST_DEC_J 期间
|
||
// cin_rd_addr 多路复用使用 dj_c_idx);数据在下一个
|
||
// 周期到达,匹配此字节的写回。
|
||
dj_byte <= dj_byte + 8'd1;
|
||
end else begin
|
||
dj_wb_vld <= 1'b0;
|
||
dj_byte <= 8'd0;
|
||
dj_mbvalid <= 1'b1;
|
||
dj_mblast <= (dj_blk == dj_nblk - 4'd1);
|
||
dj_phase <= 2'd1;
|
||
end
|
||
end
|
||
2'd1: begin
|
||
if (dj_mbvalid && !h_mbready) begin
|
||
dj_mbvalid <= 1'b0;
|
||
dj_mblast <= 1'b0;
|
||
dj_phase <= 2'd2;
|
||
end
|
||
end
|
||
2'd2: begin
|
||
if (sha3_vo) begin
|
||
kbar_r <= sha3_hash[255:0];
|
||
dj_done <= 1'b1;
|
||
dj_phase<= 2'd3;
|
||
end else if (h_mbready) begin
|
||
dj_blk <= dj_blk + 4'd1;
|
||
dj_phase <= 2'd0;
|
||
end
|
||
end
|
||
default: ; // 完成
|
||
endcase
|
||
end
|
||
|
||
// 重加密完成时武装 D7 比较(ST_ENC_C2 -> ST_DEC_CMP)。
|
||
if (st == ST_ENC_C2 && st_next == ST_DEC_CMP) begin
|
||
cmp_idx <= 11'd0;
|
||
cmp_ph <= 1'b0;
|
||
cmp_neq <= 1'b0;
|
||
cmp_done <= 1'b0;
|
||
end
|
||
|
||
// ---- ST_DEC_CMP (D7): 常量时间 c' == c 比较 + ss 选择 ----
|
||
// ph0: 向 ct_bram (c') 和 c_in_bram (c) 呈现 cmp_idx。
|
||
// ph1: 寄存读取有效 -> 将任何差异 OR 到 cmp_neq,
|
||
// 推进。最后一个字节后,锁存 dec_reject,ss 保持
|
||
// K' (ss_r) 或通过 ss_o 多路复用器切换到 K-bar (kbar_r)。
|
||
if (st == ST_DEC_CMP && !cmp_done) begin
|
||
if (!cmp_ph) begin
|
||
cmp_ph <= 1'b1; // 地址已呈现;等待读取
|
||
end else begin
|
||
cmp_neq <= cmp_neq | cmp_byte_neq;
|
||
if (cmp_idx == ct_bytes_rt - 12'd1) begin
|
||
dec_reject <= cmp_neq | cmp_byte_neq; // 包含最终字节
|
||
cmp_done <= 1'b1;
|
||
end else begin
|
||
cmp_idx <= cmp_idx + 11'd1;
|
||
end
|
||
cmp_ph <= 1'b0;
|
||
end
|
||
end
|
||
|
||
if (st_next == ST_ENC_LOAD &&
|
||
(st == ST_ENC_G || st == ST_DEC_J)) begin
|
||
rl_idx <= 6'd0;
|
||
rl_widx <= 6'd0;
|
||
rl_vld <= 1'b0;
|
||
end
|
||
|
||
// ---- ST_ENC_LOAD: 从 ek_bram 流式输入 32 个 rho 字节到 rho_r ----
|
||
// ek 读取是寄存的(1 周期延迟):本周起到达的数据
|
||
// 对应上一周期呈现的地址 (rl_idx-1)。呈现地址
|
||
// rl_idx(有效 0..31);当 rl_idx 在 1..32 时写入 rho_r[rl_idx-1]。
|
||
if (st == ST_ENC_LOAD) begin
|
||
if (rl_idx >= 6'd1 && rl_idx <= 6'd32)
|
||
rho_r[(rl_idx-6'd1)*8 +: 8] <= ek_rd_data;
|
||
rl_idx <= rl_idx + 6'd1; // 当 rl_idx >= 33 时退出
|
||
end
|
||
|
||
// 武装 ST_ENC_A(通过 SampleNTT 重新生成 A_hat,与 ST_A 相同)。
|
||
if (st == ST_ENC_LOAD && st_next == ST_ENC_A) begin
|
||
snt_valid <= 1'b1;
|
||
snt_ack <= 1'b1;
|
||
a_pair <= 5'd0;
|
||
a_i <= 3'd0;
|
||
a_j <= 3'd0;
|
||
a_widx <= 8'd0;
|
||
a_busy <= 1'b0;
|
||
end
|
||
|
||
// 武装 ST_ENC_TDEC(byteDecode12: ek -> t_hat 在 bank_a 中)。现在紧跟
|
||
// E5 (ST_ENC_C1),因为 e2 在 C/N/U 期间占用 bank_t,而 t_hat
|
||
// 仅 V 需要。(在 E1 支架中原来在 ST_ENC_A 之后武装。)
|
||
if (st == ST_ENC_C1 && st_next == ST_ENC_TDEC) begin
|
||
td_poly <= 3'd0;
|
||
td_trip <= 8'd0;
|
||
td_ph <= 3'd0;
|
||
td_done <= 1'b0;
|
||
end
|
||
// DECOMP 完成时武装 D2 s_hat 解码(ST_DEC_SDEC):相同的 TDEC
|
||
// 机,byteDecode12 dk_pke -> s_hat 在 bank_a 槽位 j*K。
|
||
if (st == ST_DEC_DECOMP && st_next == ST_DEC_SDEC) begin
|
||
td_poly <= 3'd0;
|
||
td_trip <= 8'd0;
|
||
td_ph <= 3'd0;
|
||
td_done <= 1'b0;
|
||
end
|
||
|
||
// Encaps: ek -> t_hat。Decaps D2: dk_pke -> s_hat。每个三元组
|
||
// 相同的 5 周期微相;仅字节来源 (td_byte) 不同。
|
||
if ((st == ST_ENC_TDEC || st == ST_DEC_SDEC) && !td_done) begin
|
||
// 捕获上一周期呈现地址对应的到达字节
|
||
if (td_ph == 3'd1) td_b0 <= td_byte;
|
||
if (td_ph == 3'd2) td_b1 <= td_byte;
|
||
if (td_ph == 3'd3) td_b2 <= td_byte;
|
||
|
||
// 将解码系数写入 bank_a 槽位 td_poly*K(因此 V 的 MAC
|
||
// 通过相同的 u_aslot=u_j*K 寻址读取 t_hat[j],u_row=0)。
|
||
if (td_ph == 3'd3) begin
|
||
td_we <= 1'b1;
|
||
td_wa <= (({4'd0,td_poly}*{9'd0,k_r})*256 + {td_trip, 1'b0}) & ((1<<PA_AW)-1); // 2*trip
|
||
td_wd <= td_c0;
|
||
end
|
||
if (td_ph == 3'd4) begin
|
||
td_we <= 1'b1;
|
||
td_wa <= (({4'd0,td_poly}*{9'd0,k_r})*256 + {td_trip, 1'b0} + 1) & ((1<<PA_AW)-1); // 2*trip+1
|
||
td_wd <= td_c1;
|
||
end
|
||
|
||
// 推进微相 / 三元组 / 多项式
|
||
if (td_ph == 3'd4) begin
|
||
td_ph <= 3'd0;
|
||
if (td_trip == 8'd127) begin
|
||
td_trip <= 8'd0;
|
||
if (td_poly + 3'd1 < k_r) td_poly <= td_poly + 3'd1;
|
||
else td_done <= 1'b1;
|
||
end else begin
|
||
td_trip <= td_trip + 8'd1;
|
||
end
|
||
end else begin
|
||
td_ph <= td_ph + 3'd1;
|
||
end
|
||
end
|
||
|
||
// TDEC 完成时武装 ST_ENC_E2MV: 将 e2(bank_t 相对 0)复制到
|
||
// bank_a[E2_ASLOT]。em_ridx 是预读指针(bank_t 读取是
|
||
// 寄存的,1 周期延迟);em_we/em_widx 延迟 1 周期。
|
||
if (st == ST_ENC_TDEC && st_next == ST_ENC_E2MV) begin
|
||
em_ridx <= 9'd0;
|
||
em_widx <= 8'd0;
|
||
em_we <= 1'b0;
|
||
em_done <= 1'b0;
|
||
end
|
||
|
||
// ---- ST_ENC_E2MV: e2 bank_t[0] -> bank_a[E2_ASLOT], 256 个系数 ----
|
||
// 呈现读取地址 em_ridx(bank_t 相对 0);bank_t 读取是寄存的
|
||
// 因此下一周期 bt_rd_data = e2[em_ridx]。将 bank_a 写入
|
||
// (em_we/em_widx) 安排在该下一周期,em_widx == em_ridx,因此
|
||
// 写入将 e2[R] 提交到槽位[R](无偏移错误)。
|
||
if (st == ST_ENC_E2MV && !em_done) begin
|
||
if (em_ridx <= 9'd255) begin // 本周起呈现有效的 e2 地址
|
||
em_we <= 1'b1; // -> 下周起写入(ba_wd = bt_rd_data)
|
||
em_widx <= em_ridx[7:0];
|
||
end
|
||
if (em_ridx == 9'd256) em_done <= 1'b1; // 最后写入(e2[255])已发出
|
||
else em_ridx <= em_ridx + 9'd1;
|
||
end
|
||
|
||
// e2 搬迁完成时武装 ST_ENC_V:启动首(唯一)行 MAC (i=0,j=0)。
|
||
// 重用 u_* MAC/INTT/ADD 机,u_row 固定为 0。
|
||
if (st == ST_ENC_E2MV && st_next == ST_ENC_V) begin
|
||
u_row <= 3'd0;
|
||
u_sub <= 2'd0; // MAC
|
||
u_j <= 3'd0;
|
||
u_ld <= 9'd0;
|
||
u_oidx <= 8'd0;
|
||
u_loading <= 1'b1;
|
||
u_pending <= 1'b0;
|
||
pm_valid <= 1'b0;
|
||
end
|
||
|
||
// D2 NTT 完成时武装 D3 (ST_DEC_W):相同的 u_* MAC/INTT 机,
|
||
// 单行 (u_row 0..0)。MAC s_hat[j] o u_hat[j], INTT, 然后 SUB。
|
||
if (st == ST_DEC_NTT && st_next == ST_DEC_W) begin
|
||
u_row <= 3'd0;
|
||
u_sub <= 2'd0; // MAC
|
||
u_j <= 3'd0;
|
||
u_ld <= 9'd0;
|
||
u_oidx <= 8'd0;
|
||
u_loading <= 1'b1;
|
||
u_pending <= 1'b0;
|
||
pm_valid <= 1'b0;
|
||
end
|
||
|
||
// D3 w 完成时武装 D4 (ST_DEC_MENC):byteEncode_1(Compress_1(w))。
|
||
if (st == ST_DEC_W && st_next == ST_DEC_MENC) begin
|
||
men_idx <= 8'd0;
|
||
men_ph <= 2'd0;
|
||
men_done <= 1'b0;
|
||
end
|
||
|
||
// ---- ST_DEC_MENC (D4): m' = byteEncode_1(Compress_1(w)) ----
|
||
// Compress_1(w)=1 当且仅当 832 < w <= 2496 (Q=3329)。将 256 位
|
||
// LSB-first 打包到 m_r(位 men_idx)。从 bank_t[UPSUM] 读取 w。
|
||
// ph0: 呈现 w[men_idx] 地址;ph1: bt_rd_data 有效 -> 设置位。
|
||
if (st == ST_DEC_MENC && !men_done) begin
|
||
case (men_ph)
|
||
2'd0: men_ph <= 2'd1; // 地址已呈现;等待读取
|
||
default: begin // ph1: bt_rd_data = w[men_idx]
|
||
m_r[men_idx] <= men_w_bit;
|
||
if (men_idx == 8'd255) men_done <= 1'b1;
|
||
else men_idx <= men_idx + 8'd1;
|
||
men_ph <= 2'd0;
|
||
end
|
||
endcase
|
||
end
|
||
end
|
||
end
|
||
|
||
endmodule
|