This repository has been archived on 2026-08-21. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
ciciec2026/rtl/ip/mlkem/top/mlkem_top.v
2026-07-04 18:53:23 +08:00

2250 lines
118 KiB
Verilog
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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_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