// 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<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< 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<= 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 时)。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 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< 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