diff --git a/doc/mlkem_axi_slave_regs.md b/doc/mlkem_axi_slave_regs.md new file mode 100644 index 0000000..a225417 --- /dev/null +++ b/doc/mlkem_axi_slave_regs.md @@ -0,0 +1,262 @@ +# ML-KEM AXI Slave 寄存器参考手册 + +## 概述 + +`mlkem_axi_slave` 是 ML-KEM 硬件加速器的 AXI4 Slave 总线接口。它封装 `mlkem_top` 核心,提供完整的寄存器映射用于软件控制 KeyGen / Encaps / Decaps 操作。 + +### 关键特性 + +- **总线**: AXI4 (支持 INCR burst read/write) +- **基址**: `0xbf400000`(LoongArch 虚地址) +- **时钟域**: sys_clk (50 MHz) → mlkem_clk (25 MHz),跨域通过 toggle 握手同步 +- **支持参数**: k=2 (ML-KEM-512), k=3 (ML-KEM-768), k=4 (ML-KEM-1024) +- **中断**: `intr` 信号,当 done 标志锁存时电平有效高 + +--- + +## 寄存器映射 + +所有寄存器为 32-bit 对齐。偏移量相对于基址 `0xbf400000`。 + +| 偏移 | 名称 | 访问 | 复位值 | 描述 | +|------|------|------|--------|------| +| `0x000` | **CTRL** | W | `0x00000000` | 控制寄存器:写 bit0=1 启动操作 | +| `0x004` | **STATUS** | R/W1C | `0x00000000` | 状态寄存器 | +| `0x008` | **CONFIG** | RW | `0x00000004` | 配置寄存器:k 值和操作码 | +| `0x010`–`0x02C` | **D[0..7]** | RW | `0x00000000` | KeyGen 种子 d(256-bit,8字) | +| `0x030`–`0x04C` | **Z[0..7]** | RW | `0x00000000` | KeyGen 隐式拒绝种子 z(256-bit,8字) | +| `0x050`–`0x06C` | **MSG[0..7]** | RW | `0x00000000` | Encaps 消息 m(256-bit,8字) | +| `0x070`–`0x08C` | **SS[0..7]** | R | — | 共享密钥输出(256-bit,8字,只读) | +| `0x100` | **PRELOAD_SEL** | RW | `0x00000000` | 预载端口选择 | +| `0x104` | **PRELOAD_ADDR** | RW | `0x00000000` | 预载字节地址(写入后自动递增) | +| `0x108` | **PRELOAD_DATA** | W | — | 预载数据字节(写低 8-bit,自动 wait-state) | +| `0x10C` | **READBACK_SEL** | RW | `0x00000000` | 回读端口选择 | +| `0x110` | **READBACK_ADDR** | RW | `0x00000000` | 回读字节索引(无自动递增) | +| `0x114` | **READBACK_DATA** | R | — | 回读数据字节(低 8-bit 有效) | + +--- + +## 寄存器详情 + +### CTRL (0x000) — 控制寄存器,只写 + +| Bits | 名称 | 描述 | +|------|------|------| +| `0` | **start** | 写 `1` 启动当前 CONFIG 中配置的操作。写 `0` 无效。 | + +- 写 start 后,STATUS.busy 立即置位,done 清零。 +- 操作完成前不可再次启动。 +- CTRL 本身不可读(读返回 0)。 + +--- + +### STATUS (0x004) — 状态寄存器,读/写1清零 + +| Bits | 名称 | 访问 | 描述 | +|------|------|------|------| +| `0` | **busy** | R | 核心正在执行操作(KeyGen/Encaps/Decaps) | +| `1` | **done** | R/W1C | 操作已完成。写 `1` 清除(写 `0` 无效)。启动新操作时自动清除 | +| `2` | **preload_busy** | R | 预载数据传输正在进行中(跨域字节握手未完成) | +| `31:3` | — | — | 保留,读为 0 | + +**注意**: +- `done` 是**锁存**标志:操作完成后保持为 1,直到软件写 1 清零或启动新操作。 +- `busy` 和 `done` **不互斥**:在 done 置位的同一周期 busy 清零,两者可能同时为 1(短暂窗口)。 +- `preload_busy` 为 1 时,写入 PRELOAD_DATA 会被 wait-state 直到传输完成。 + +--- + +### CONFIG (0x008) — 配置寄存器,读写 + +| Bits | 名称 | 复位值 | 描述 | +|------|------|--------|------| +| `2:0` | **k** | `3'b100` (4) | ML-KEM 参数:`2`=ML-KEM-512, `3`=ML-KEM-768, `4`=ML-KEM-1024 | +| `4` | — | `0` | 保留 | +| `5:4` | **op** | `2'b00` | 操作码:`0`=KeyGen, `1`=Encaps, `2`=Decaps | +| `31:6` | — | `0` | 保留 | + +**约束**: +- 修改 CONFIG 应在启动操作之前完成。启动后修改可能导致未定义行为。 +- k 必须为 2、3 或 4。 + +--- + +### D[0..7] (0x010–0x02C) — KeyGen 种子 d,读写 + +256-bit 种子 `d`,用于 KeyGen 操作。存储为 8 个 32-bit 字,小端序: + +| 字偏移 | 地址 | 包含字节 | +|--------|------|---------| +| D[0] | `0x010` | d[3:0](字节 3 在 bit[31:24],字节 0 在 bit[7:0]) | +| D[1] | `0x014` | d[7:4] | +| ... | ... | ... | +| D[7] | `0x02C` | d[31:28] | + +核心看到的 256-bit 总线为 `{D[7], D[6], ..., D[0]}`,其中 `d_i[7:0]` = D[0][7:0]。 + +支持 AXI wstrb 按字节写入。 + +--- + +### Z[0..7] (0x030–0x04C) — 隐式拒绝种子 z,读写 + +256-bit 种子 `z`,用于 KeyGen。布局与 D 相同。 + +--- + +### MSG[0..7] (0x050–0x06C) — Encaps 消息 m,读写 + +256-bit 消息 `m`,用于 Encaps。布局与 D 相同。 + +--- + +### SS[0..7] (0x070–0x08C) — 共享密钥,只读 + +256-bit 共享密钥输出。KeyGen 和 Encaps 操作完成后在此处提供结果。 + +| 字偏移 | 地址 | 内容 | +|--------|------|------| +| SS[0] | `0x070` | ss[31:0] | +| SS[1] | `0x074` | ss[63:32] | +| ... | ... | ... | +| SS[7] | `0x08C` | ss[255:224] | + +--- + +### PRELOAD_SEL (0x100) — 预载端口选择,读写 + +| Bits | 名称 | 描述 | +|------|------|------| +| `1:0` | **sel** | 预载目标端口:`0`=ek, `1`=dk, `2`=c(密文) | +| `31:2` | — | 保留 | + +设置后,随后写入 PRELOAD_DATA 的字节将流向所选端口。 + +--- + +### PRELOAD_ADDR (0x104) — 预载字节地址,读写 + +| Bits | 名称 | 描述 | +|------|------|------| +| `11:0` | **addr** | 预载端口内的字节偏移地址。每次 PRELOAD_DATA 写入成功后自动递增 | +| `31:12` | — | 保留 | + +写入 PRELOAD_DATA 前必须先设置好 PRELOAD_SEL 和 PRELOAD_ADDR(通常 addr=0)。 + +--- + +### PRELOAD_DATA (0x108) — 预载数据字节,只写 + +| Bits | 名称 | 描述 | +|------|------|------| +| `7:0` | **byte** | 写入所选预载端口的字节数据 | +| `31:8` | — | 忽略 | + +此寄存器**自动 wait-state**:写入后 AXI 总线暂停,直到跨域握手完成(字节被 mlkem 核心采样)。然后 PRELOAD_ADDR 自动递增 1。 + +**重要**: 每个字节需要一次 AXI 写事务。对于大数据量(ek=800B, dk=1632B),建议使用 INCR burst 写,burst 长度设为字节数。 + +--- + +### READBACK_SEL (0x10C) — 回读端口选择,读写 + +| Bits | 名称 | 描述 | +|------|------|------| +| `1:0` | **sel** | 回读源:`0`=ek, `1`=dk_pke, `2`=完整 dk, `3`=密文 | +| `31:2` | — | 保留 | + +--- + +### READBACK_ADDR (0x110) — 回读字节索引,读写 + +| Bits | 名称 | 描述 | +|------|------|------| +| `11:0` | **addr** | 待读取字节在回读端口中的索引。**无自动递增** | +| `31:12` | — | 保留 | + +每个字节的读取流程:写 READBACK_ADDR → 读 READBACK_DATA。 + +--- + +### READBACK_DATA (0x114) — 回读数据字节,只读 + +| Bits | 名称 | 描述 | +|------|------|------| +| `7:0` | **byte** | 所选回读端口中 READBACK_ADDR 索引处的字节 | +| `31:24` | — | 读为 0 | + +--- + +## 操作流程 + +### 1. KeyGen: (d, z) → ek, dk + +``` +1. 写 CONFIG: op=0 (KeyGen), k=2/3/4 +2. 写 D[0..7] ← 种子 d (256-bit) +3. 写 Z[0..7] ← 种子 z (256-bit) +4. 写 CTRL: bit0=1 → 启动 +5. 轮询 STATUS.done == 1(或等待 intr) +6. 通过 READBACK 读取 ek 和 dk: + a. RDB_SEL=0, 逐个字节读 ADDR=0..799 → ek (800 B for k=2) + b. RDB_SEL=2, 逐个字节读 ADDR=0..1631 → dk (1632 B for k=2) +7. 读 SS[0..7] → 共享密钥(可选) +8. 写 STATUS: bit1=1 → 清除 done +``` + +### 2. Encaps: (ek, m) → (ss, ct) + +``` +1. 写 CONFIG: op=1 (Encaps), k=2/3/4 +2. 通过 PRELOAD 预载 ek: + a. PRE_SEL=0, PRE_ADR=0 + b. 逐个字节写 PRE_DAT (800 B for k=2) +3. 写 MSG[0..7] ← 消息 m (256-bit) +4. 写 CTRL: bit0=1 → 启动 +5. 轮询 STATUS.done == 1 +6. 读 SS[0..7] → 共享密钥 +7. 通过 READBACK 读取 ct: + a. RDB_SEL=3, 逐个字节读 ADDR=0..767 → ct (768 B for k=2) +``` + +### 3. Decaps: (dk, ct) → ss + +``` +1. 写 CONFIG: op=2 (Decaps), k=2/3/4 +2. 通过 PRELOAD 预载 dk 和 ct: + a. PRE_SEL=1, PRE_ADR=0, 逐个字节写 PRE_DAT (1632 B for k=2) + b. PRE_SEL=2, PRE_ADR=0, 逐个字节写 PRE_DAT (768 B for k=2) +3. 写 CTRL: bit0=1 → 启动 +4. 轮询 STATUS.done == 1 +5. 读 SS[0..7] → 共享密钥 +``` + +--- + +## 数据尺寸参考 + +| 参数 | k=2 (ML-KEM-512) | k=3 (ML-KEM-768) | k=4 (ML-KEM-1024) | +|------|-------------------|-------------------|---------------------| +| ek 字节数 | 800 | 1184 | 1568 | +| dk_pke 字节数 | 768 | 1152 | 1536 | +| dk 总字节数 | 1632 | 2400 | 3168 | +| ct 字节数 | 768 | 1088 | 1568 | + +--- + +## 中断 + +- `intr` 信号在 `STATUS.done == 1` 时保持高电平。 +- 清除中断:写 `STATUS` 的 bit1=1(W1C)或启动新操作。 +- `intr` 是电平触发(非脉冲),连接到 LoongArch 的 HWI 输入。 + +--- + +## 注意事项 + +1. **时钟域**: 核心运行在 sys_clk/2 (25 MHz)。PRELOAD_DATA 写入自动 wait-state,软件无需处理跨域延迟。 +2. **启动时序**: 确保在写 CTRL.start 之前,config/seeds/preload 数据已全部写入且稳定。 +3. **PRELOAD_ADDR 自动递增**: 连续写 PRELOAD_DATA 时地址自动递增,无需手动更新 PRELOAD_ADDR(除非切换端口)。 +4. **READBACK_ADDR 无自动递增**: 每次读 READBACK_DATA 前必须手动写 READBACK_ADDR。 +5. **done 标志**: 是锁存的,启动新操作时自动清除。连续执行多个操作时,每次启动前先确认 busy==0,然后清 done。 +6. **STATUS 读取时机**: done 标志在操作完成的 mlkem_clk 周期后,需经 2 级同步器(~40ns)才能在 sys_clk 域看到。 diff --git a/rtl/ip/mlkem/top/mlkem_top.v b/rtl/ip/mlkem/top/mlkem_top.v index 3c554bf..6beaefa 100644 --- a/rtl/ip/mlkem/top/mlkem_top.v +++ b/rtl/ip/mlkem/top/mlkem_top.v @@ -1,178 +1,180 @@ -// mlkem_top.v - ML-KEM KeyGen top-level integration. Runtime-selectable -// parameter set via k_i: k=2 (ML-KEM-512, eta1=3), k=3 (768), k=4 (1024). -// Storage is sized for KMAX (worst case = ML-KEM-1024); k_i picks the -// active sub-range at start_i. +// 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 时 +// 选择有效子范围。 // -// Streaming valid/ready interface. Given seeds d and z, computes the -// ML-KEM key pair per FIPS 203 Algorithm 16 (KeyGen_internal): +// 流式 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 in 0..K-1 +// 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 // -// Built incrementally and verified stage-by-stage against reference golden -// vectors (test_framework/modules/mlkem_keygen/golden) and NIST KAT. +// 按阶段增量构建,并针对参考黄金向量 +// (test_framework/modules/mlkem_keygen/golden) 和 NIST KAT 进行逐阶段验证。 // -// Uses independent (verified) leaf modules over a shared keccak_core: +// 使用独立(已验证)的叶子模块,共享同一个 keccak_core: // sha3_top_shared, sample_ntt_sync_shared, sample_cbd_sync_shared, ntt_core, -// poly_mul_sync, comp_decomp_sync. +// poly_mul_sync, comp_decomp_sync。 `include "defines.vh" (* use_dsp = "no" *) module mlkem_top #( - parameter KMAX = 4 // storage sizing (worst case = ML-KEM-1024) + parameter KMAX = 4 // 存储器大小(最坏情况 = ML-KEM-1024) ) ( input clk, input rst_n, - input [2:0] k_i, // RUNTIME ML-KEM param: 2=512, 3=768, 4=1024 - input [1:0] op_i, // 0=KeyGen, 1=Encaps, 2=Decaps (captured at start_i) - input [255:0] d_i, // KeyGen seed d (byte 0 in d_i[7:0]) - input [255:0] z_i, // implicit-rejection seed z - input [255:0] msg_i, // Encaps message m (byte 0 in msg_i[7:0]) - input start_i, // pulse to begin KeyGen - output busy_o, // high while running - output done_o, // pulse when ek/dk ready + 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 input: stream ek bytes (=pk) into ek_bram before start_i with - // op_i=1. ek_in_we writes byte ek_in_byte at address ek_in_addr. - input ek_in_we, // write one ek byte (only honored in ST_IDLE for Encaps preload) - input [10:0] ek_in_addr, // ek byte address 0..ek_bytes-1 - input [7:0] ek_in_byte, // ek byte value - // Decaps dk input: stream dk bytes (=sk, 768K+96) into the design before - // start_i with op_i=2. The load logic routes each byte by region: - // [0,384K) -> dk_pke (dkp_bram) = s_hat encoding - // [384K, 768K+32) -> ek_pke (ek_bram) = t_hat encoding || rho + // 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, // write one dk byte (ST_IDLE Decaps preload) - input [11:0] dk_in_addr, // dk byte address 0..(768K+96)-1 - input [7:0] dk_in_byte, // dk byte value - // Decaps ciphertext input: stream c bytes (=ct) into c_in_bram before - // start_i. Kept separate from ct_bram so the computed c' can be compared - // against the original c (and J(z||c) can read c) without aliasing. - input c_in_we, // write one c byte (ST_IDLE Decaps preload) - input [10:0] c_in_addr, // c byte address 0..ct_bytes-1 - input [7:0] c_in_byte, // c byte value - // Encaps shared secret output (= K), valid at done_o + 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 ciphertext readback tap: ct byte by index 0..ct_bytes-1 + // Encaps 密文回读抽头:按索引 0..ct_bytes-1 输出 ct 字节 input [10:0] dbg_ct_idx_i, output [7:0] dbg_ct_o, - // Debug readback tap: read one stored coefficient by (poly slot, index). - // Lets stage TBs verify intermediates without wide buses. - input [5:0] dbg_slot_i, // poly slot (see localparams below) - input [7:0] dbg_idx_i, // coefficient index 0..255 + // Debug 回读抽头:按(多项式槽位,索引)读取一个存储系数。 + // 允许各阶段测试平台验证中间结果,无需宽总线。 + input [5:0] dbg_slot_i, // 多项式槽位(见下面的 localparam) + input [7:0] dbg_idx_i, // 系数索引 0..255 output [11:0] dbg_coeff_o, - // Debug byte readback: ek (sel=0, 0..799) / dk_pke (sel=1, 0..767) + // 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 full-dk readback: dk = dk_pke(768) || ek(800) || H(ek)(32) || z(32) - // = 1632 bytes. Index 0..1631. + // 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 taps for hash outputs + // Debug 哈希输出抽头 output [255:0] dbg_rho_o, output [255:0] dbg_sigma_o, - // Encaps debug taps: r (G high half) and H(ek) + // Encaps debug 抽头:r(G 高半部分)和 H(ek) output [255:0] dbg_r_o, output [255:0] dbg_hek_o, - // Decaps debug taps: m' (Decrypt output), K-bar (J output), parsed z/h. + // 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, // parsed z (dk[768K+64:+32]) - output [255:0] dbg_dech_o // parsed H(ek) (dk[768K+32:+32]) + 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 - // Runtime ML-KEM parameter, captured at start_i. + // 运行时 ML-KEM 参数,在 start_i 时捕获。 reg [2:0] k_r; - // FIPS 203: eta1 = 3 for ML-KEM-512 (k=2), else 2 (k=3/4). + // 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; - // Runtime-derived sizes (k_r in {2,3,4}). Small multiplies are cheap. + // 运行时推导的大小(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 base slot - wire [5:0] slot_e_rt = kk_rt + k_r; // e_hat base slot - wire [5:0] slot_t_rt = kk_rt + {1'b0, k_r} + {1'b0, k_r}; // t_hat base = kk+2k + 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 - // full dk = dk_pke(dk_bytes) || ek(ek_bytes) || H(ek)(32) || z(32). Region - // boundaries (used by Decaps dk load routing and dk readback). - wire [11:0] dk_ek_end = dk_bytes_rt + ek_bytes_rt; // ek_pke region end - wire [11:0] dk_hek_end = dk_ek_end + 12'd32; // H(ek) region end - // LOAD-TIME boundaries: dk is streamed in BEFORE start_i, so k_r is not yet - // captured. Route the dk load by the LIVE k_i input instead of k_r. + // 完整 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 region end - wire [11:0] dk_hek_end_ld= dk_ek_end_ld + 12'd32; // H(ek) region end - // H(ek) block count = ceil((ek_bytes+1)/136): 6/9/12 for k=2/3/4 (table) + 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; // final padded byte index + wire [11:0] h_last_rt = {6'b0, h_nblk_rt} * 12'd136 - 12'd1; // 最终填充字节索引 - // ---- Encaps runtime params ---- - reg [1:0] op_r; // 0=KeyGen 1=Encaps 2=Decaps (captured at start) - reg [255:0] m_r; // Encaps message m (captured at start); Decaps reuses for m' - reg [255:0] ss_r; // Encaps shared secret K (= G output low half) - reg [255:0] r_r; // Encaps PRF seed r (= G output high half) - // ---- Decaps runtime params (parsed from dk during load) ---- - reg [255:0] z_r; // implicit-rejection seed z (dk tail), captured at load - reg [255:0] kbar_r; // K-bar = J(z||c) (D5) - // FIPS 203: eta2 = 2 for all parameter sets. + // ---- 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; - // Compression params: (du,dv) = (10,4) for k=2/3, (11,5) for k=4. + // 压缩参数:(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; - // Ciphertext byte sizes: c1 = 32*du*k, c2 = 32*dv, ct = c1+c2. + // 密文字节大小: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 - // Shared secret out: Encaps drives ss_r = K directly. Decaps implicit reject: - // ss = (c' == c) ? K' : K-bar. K' is in ss_r, K-bar in kbar_r; dec_reject is - // the latched c' != c flag from D7 (0 for KeyGen/Encaps, so ss_r passes through). + // 共享密钥输出: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-load + byteDecode12 bookkeeping ---- - // rho load: read 32 bytes from ek_bram at offset 384*k into rho_r. - reg [5:0] rl_idx; // 0..33 read-ahead pointer over rho bytes - reg [5:0] rl_widx; // 0..31 byte being written (1 cyc behind rl_idx) - reg rl_vld; // a byte is arriving this cycle - wire [11:0] rl_ek_off = dk_bytes_rt + {6'b0, rl_idx}; // ek addr = 384k + idx - // byteDecode12: read 3 ek bytes -> 2 coeffs into bank_t. Walk K polys * 128 - // triples. 5-cycle micro-phase per triple: ph0..2 fetch b0,b1,b2 (read-ahead, - // 1-cycle bram latency), ph3 write c0, ph4 write c1. - reg [2:0] td_poly; // 0..k-1 t_hat poly index - reg [7:0] td_trip; // 0..127 triple within poly - reg [2:0] td_ph; // 0..4 micro-phase - reg [7:0] td_b0, td_b1, td_b2; // captured ek bytes + // ---- 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 byte address for the triple: poly*384 + trip*3 + (ph for ph<3) - wire [11:0] td_base = {td_poly, 7'd0} * 12'd3; // poly*384 (=poly*256*1.5)... see below - // poly*384 + trip*3 + byteidx; byteidx = ph (0,1,2) during fetch phases + // 三元组的 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}; - // decoded coeffs: c0 = b0 | ((b1&0xF)<<8); c1 = (b1>>4) | (b2<<4) + // 解码后的系数: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 byte source: Encaps reads ek (ek_rd_data); Decaps D2 (ST_DEC_SDEC) - // reuses the same machine to byteDecode12 dk_pke -> s_hat, reading dkp_bram. + // 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; - // bank_a write for TDEC (registered); t_hat[td_poly] -> bank_a slot - // td_poly*K. td_wa is a bank_a byte address (PA_AW=12). + // 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 address (PA_AW=12) + reg [11:0] td_wa; // bank_a 地址 (PA_AW=12) reg [11:0] td_wd; - // ---- ct_bram: ciphertext byte buffer (<=1568 B). Written by E5/E7 - // (compress + byteEncode_du/dv), read back via dbg_ct tap. ---- + // ---- 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; @@ -183,64 +185,64 @@ module mlkem_top #( .rd_addr(ct_rd_addr), .rd_data(ct_rd_data), .wr_en(ct_we), .wr_addr(ct_wa), .wr_data(ct_wd) ); - // ct_bram read addr: D7 compare walks c' via cmp_idx; else debug readback. + // 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 input ciphertext c (<=1568 B). Preloaded via - // c_in_* in ST_IDLE. Kept separate from ct_bram (which holds the computed - // c') so D7 can compare c' vs c and D5 J(z||c) can read c. Read port is - // muxed (D5 J-feed / D7 compare); for D0 only the load write path exists. + // ---- 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 read address (tied 0 until then) + 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 read addr: D5 J presents dj_c_idx combinationally (no extra register - // stage) so the registered BRAM read yields the byte 1 cycle later, matching - // the assemble/writeback pipeline. Otherwise the registered cin_rd_addr_r - // (D1 walker / idle) drives it. + // 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; // ================================================================ - // Polynomial storage, sized for KMAX (worst case). Runtime k uses a - // sub-range. Slot layout (each slot = 256 coeffs): - // A_hat[i][j] : slots 0 .. k*k-1 at index i*k + j - // s_hat[i] : slots slot_s_rt .. +k-1 - // e_hat[i] : slots slot_e_rt .. +k-1 - // t_hat[i] : slots slot_t_rt .. +k-1 - // NUM_SLOTS = KMAX*KMAX + 3*KMAX = 28 for KMAX=4. + // 多项式存储,按 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; // slot-address width (>=clog2(28)) + localparam SAW = 5; // 槽位地址宽度(>=clog2(28)) // ================================================================ - // Coefficient storage as 3 banks (Phase 2). Was one async-read reg - // array polymem[0:28*256-1]; split by polynomial so each becomes a - // registered-read sd_bram (infers BRAM / ASIC SRAM) in the final step. - // bank_a : A_hat[i][j] slots 0..K^2-1 -> D=KMAX*KMAX*256=4096 - // bank_se: s_hat||e_hat slots slot_s.. -> D=2*KMAX*256=2048 (rel 0..2K-1) - // bank_t : t_hat[i] slots slot_t.. -> D=KMAX*256=1024 (rel 0..K-1) - // Addresses are base-relative: bank index = abs_slot - base_slot. - // Stage 2b (in progress): per-consumer registered read-ahead. Banks are - // still async reg arrays here; converted consumers read via their own - // 1-cycle pipeline reg (== sd_bram timing). Once every consumer of a - // bank is registered, the array is replaced by an sd_bram with its read - // port muxed across the (phase-disjoint) consumers. + // 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 addr width (4096) - localparam PSE_AW = 11; // bank_se addr width (2048) - localparam PT_AW = 10; // bank_t addr width (1024) + 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. Reader = ST_M load (pm_a) + dbg. Writer = ST_A. - // Read port muxed by phase; sd_bram's internal rd_addr_r register is the - // 1-cycle read pipeline (replaces the explicit pm_a_rd reg). Write port is - // driven combinationally (sd_bram registers the write at posedge, matching - // the old reg-array nonblocking write timing). + // 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; @@ -250,28 +252,30 @@ module mlkem_top #( .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 write: commit snt_coeff to A_hat[a_slot] when accepted. - // Encaps E6 also writes t_hat here via byteDecode12 (TDEC): t_hat[j] lands - // in bank_a at slot j*K so V's MAC reuses E4's u_aslot=u_j*K (u_row=0) addr. - // ST_ENC_E2MV writes the relocated e2 into bank_a[E2_ASLOT] (em_we). - // D1 DECOMP writes v' into bank_a[DEC_VASLOT] (dec_v_we) so D3 can read it - // in parallel with the bank_t psum during the w-SUB. + // 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<0 running t_hat) + ST_E ek-half + dbg. - // Writer = ST_M acc. Read port muxed by phase; sd_bram's rd_addr_r is the - // 1-cycle read register. RMW is safe: the acc read addr leads the write - // addr by 1 (m_oidx+1 vs m_oidx), so read/write never alias in a cycle and - // sd_bram write-first == reg-array read-old. Write port combinational. + // 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; @@ -296,16 +300,16 @@ module mlkem_top #( .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 write: KeyGen ST_M accumulate, or Encaps e2 (ST_ENC_C c_poly==2K - // -> bank_t rel slot 0, free during C/N/U). (TDEC writes bank_a now.) + // 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 writes: MAC psum (u_sub0, on pm_vo) and INTT in-place - // (u_sub1, on ntt_vo). Both target bank_t rel slot UPSUM. ST_ENC_V (E6) adds - // the V-ADD writeback (psum + e2 + mu) at UPSUM via u_v_we below. + // 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 writeback: cd_vo while decoding c2 writes v' to bank_a[DEC_VASLOT]. + // 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 || @@ -323,58 +327,58 @@ module mlkem_top #( u_w_we ? u_wq : m_accq; - // Debug readback (registered for timing) + // Debug 回读(已寄存以改善时序) reg [11:0] dbg_coeff_r; - // Route debug read by absolute slot range (not on the KAT correctness - // path — TB reads ek/dk BRAMs only). A: 0..K^2-1; s/e: slot_s..slot_t-1; - // t: slot_t.. Index within bank is (abs_slot-base)*256 + idx. + // 按绝对槽位范围路由 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 read port: ST_M / Encaps ST_ENC_U MAC drive pm_a addr; ST_ENC_V - // MAC reads t_hat[j] (u_pm_a_full, u_row=0) and ADD reads e2 (E2_ASLOT); else dbg. + // 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 read - : u_pm_a_full[PA_AW-1:0]) : // MAC: t_hat[u_j] + ((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' read - : u_pm_a_full[PA_AW-1:0]) : // MAC: s_hat[u_j] + ((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 read port: ST_M acc (t_hat), ST_E ek-half (byteEncode), Encaps - // ST_ENC_U/V + Decaps ST_DEC_W (MAC psum acc, INTT load, or ADD/SUB psum - // read by sub-phase), ST_ENC_E2MV (e2 read from rel slot 0); else dbg. + // 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 load - u_add_prd[PT_AW-1:0]) : // ADD/SUB psum read - (st == ST_ENC_E2MV) ? em_rd[PT_AW-1:0] : // e2 relocate read + (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 read port: ST_N load (s/e NTT), ST_M load (pm_b s_hat[j]) vs - // accumulate (e_hat, mutually exclusive via m_loading), ST_E dk-half, dbg. + // 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] read + 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 write: KeyGen ST_C CBD (s/e), Encaps ST_ENC_C CBD (y/e1, c_poly<2K; - // e2 at c_poly==2K goes to bank_t instead), ST_N/ST_ENC_N NTT writeback, - // Encaps E4 ADD u-writeback (u_sub==2). - // Encaps E4 ADD: write u[u_row] over e1 in bank_se rel slot (K+u_row). + // 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 writeback: cd_vo while decoding c1 writes u'[dec_poly] to - // bank_se rel slot dec_poly (0..K-1), at coeff index dec_widx. + // 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) || @@ -396,28 +400,28 @@ module mlkem_top #( end assign dbg_coeff_o = dbg_coeff_r; - // ek and dk_pke byte memories sized for KMAX. + // ek 和 dk_pke 字节存储器按 KMAX 大小设计。 localparam EK_MAX = 384*KMAX + 32; // 1568 localparam DK_MAX = 384*KMAX; // 1536 - // ek / dk_pke byte storage in BRAM (sd_bram: 1R/1W, 1-cycle read latency). - // Each single read port is shared time-disjointly: ST_H assemble reads ek - // (in ST_H), debug readback reads ek/dk (in ST_DONE). Write port driven by - // ST_E (1 byte/cycle) and the rho-tail copy. + // 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 write port: KeyGen ST_E drives ek_we/ek_wa/ek_wd; Encaps preloads - // ek from the external ek_in_* port (TB streams ek=pk before start_i). Decaps - // routes the dk's ek_pke region (dk[384K:768K+32]) here at load time. The - // three never overlap (preloads happen in ST_IDLE before a run). + // 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 region - wire dk_ld_dkpke = dk_in_we && (dk_in_addr < dkp_bytes_ld); // dk_pke region - wire [10:0] dk_ek_off = (dk_in_addr - dkp_bytes_ld); // offset within ek + && (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 : @@ -430,9 +434,9 @@ module mlkem_top #( .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 write port: KeyGen ST_E (s_hat byteEncode) drives dkp_we/wa/wd; - // Decaps routes the dk's dk_pke region (dk[0:384K]) here at load time. The - // two never overlap (preload in ST_IDLE before a Decaps run). + // 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; @@ -442,18 +446,17 @@ module mlkem_top #( .wr_en(dkp_we_mux), .wr_addr(dkp_wa_mux), .wr_data(dkp_wd_mux) ); - // full dk = dk_pke(dk_bytes) || ek(ek_bytes) || H(ek)(32) || z(32). - // (dk_ek_end / dk_hek_end declared near the top with the other size wires.) + // 完整 dk = dk_pke(dk_bytes) || ek(ek_bytes) || H(ek)(32) || z(32)。 + //(dk_ek_end / dk_hek_end 已在顶部附近与其他大小线一起声明。) - // Debug-region selects for dk readback (combinational region decode). + // 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); - // Read-address muxes (declared here; depend on ST_H h_g defined below via - // the function-free expression h_blk*136 + h_byte). See assigns after the - // H-stage register declarations. - // dbg_byte_o / dbg_dk_o are combinational taps over the (registered) BRAM - // read data; net 1-cycle latency, well within the TB's 2-cycle read wait. + // 读取地址多路复用(在此声明;通过下方 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 : @@ -461,58 +464,58 @@ module mlkem_top #( : z_i[(dbg_dk_idx_i - dk_hek_end)*8 +: 8]; // ================================================================ - // Top-level FSM (built incrementally). Stage 2a: G only. + // 顶层 FSM(增量构建)。阶段 2a:仅 G。 // ================================================================ localparam ST_IDLE = 5'd0; - localparam ST_G = 5'd1; // run G(d||K), capture rho/sigma - localparam ST_A = 5'd2; // generate A_hat[i][j] via SampleNTT - localparam ST_C = 5'd3; // generate s[i],e[i] via CBD - localparam ST_N = 5'd4; // forward NTT of s[i],e[i] in place - localparam ST_M = 5'd5; // matrix accumulate t_hat = e_hat + sum A o s_hat + 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; // H(ek) via multi-block SHA3-256 - // ---- Encaps states ---- - localparam ST_ENC_LOAD = 5'd8; // ek already preloaded; placeholder/settle - localparam ST_ENC_H = 5'd9; // H(ek) via multi-block SHA3-256 (reuses ST_H logic) - localparam ST_ENC_G = 5'd10; // (K,r) = G(m || H(ek)), 64-byte single block - localparam ST_ENC_A = 5'd11; // regenerate A_hat (transpose used in U) - localparam ST_ENC_TDEC = 5'd12; // byteDecode12: ek -> t_hat (bank_a slot j*K) - localparam ST_ENC_C = 5'd13; // sample y,e1,e2 via CBD (eta1/eta2) - localparam ST_ENC_N = 5'd14; // forward NTT of y in place + 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; // relocate e2 bank_t[0] -> bank_a[E2_ASLOT] - // ---- Decaps states ---- - localparam ST_DEC_LOAD = 5'd20; // dk/c already streamed in; parse/settle (D0) - localparam ST_DEC_DECOMP = 5'd21; // D1: byteDecode_d + Decompress c1->u', c2->v' - localparam ST_DEC_SDEC = 5'd22; // D2: byteDecode12 dk_pke -> s_hat (bank_a slot j*K) - localparam ST_DEC_NTT = 5'd23; // D2: u_hat[i] = NTT(u'[i]) in place (bank_se rel 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 single block - localparam ST_DEC_J = 5'd27; // D5: K-bar = J(z || c), multi-block SHAKE256 - localparam ST_DEC_CMP = 5'd28; // D7: c' == c compare + implicit-reject ss select + 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-generation bookkeeping: explicit i/j counters (avoid runtime divide) - reg [2:0] a_i; // row 0..k-1 - reg [2:0] a_j; // col 0..k-1 - reg [4:0] a_pair; // 0..k*k pairs done (for done test) - reg [7:0] a_widx; // write index 0..255 within current poly - reg a_busy; // 1 once current pair's request accepted (gates collect) - wire [SAW-1:0] a_slot = a_i*k_r + a_j; // A_hat[i][j] slot = i*k + j + // 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-generation bookkeeping: 2*k polys (s[0..k-1] then e[0..k-1]) + // 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 - // slot: c_poly < k -> s_hat[c_poly], else e_hat[c_poly-k] + 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})); @@ -522,61 +525,61 @@ module mlkem_top #( assign dbg_sigma_o = sigma_r; assign dbg_r_o = r_r; assign dbg_hek_o = hek_r; - // Decaps taps: m' from D4 (written into m_r, reused by V/mu in D6 re-encrypt); - // z/h parsed from dk at load. + // 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 parses dk's H(ek) into hek_r at load + assign dbg_dech_o = hek_r; // Decaps 在加载时将 dk 的 H(ek) 解析到 hek_r - // ---- sha3_top in G mode: data_i = {K_byte, d} (d byte0 in [7:0]) ---- + // ---- 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; // consumer ready for hash - wire [511:0] kg_g_data = {248'b0, 5'b0, k_r, d_i}; // KeyGen G: [263:256]=k, [255:0]=d - wire [511:0] enc_g_data = {hek_r, m_r}; // Encaps G: m || H(ek), 64 bytes - wire [511:0] dec_g_data = {hek_r, m_r}; // Decaps D5 G: m' || h, 64 bytes + 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; // ================================================================ - // Shared keccak_core + phase mux (3 consumers -> 1 core) + // 共享 keccak_core + 相位多路复用(3 个消费者 -> 1 个核心) // - // G/H (u_sha3), SampleNTT (u_snt) and CBD (u_cbd) each need a Keccak - // permutation, but they run in DISJOINT top-FSM phases (ST_G/ST_H, ST_A, - // ST_C respectively), so at most one is ever active. One keccak_core - // serves all three: kc_state_i/kc_valid_i are muxed by phase; kc_valid_o - // is broadcast but GATED per consumer so an inactive consumer never - // latches a permutation result meant for another (the samplers latch - // squeeze state unconditionally on their kc_valid_o input). + // 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; // shared core output (to all consumers) - wire kc_valid_o; // shared core output-valid - wire kc_ready_o; // shared core input-ready + wire [1599:0] kc_state_o; // 共享核心输出(给所有消费者) + wire kc_valid_o; // 共享核心输出有效 + wire kc_ready_o; // 共享核心输入就绪 - // per-consumer drives toward the core + // 每个消费者驱动到核心 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; // all 1'b1 + wire sha3_kc_ready_i, snt_kc_ready_i, cbd_kc_ready_i; // 均为 1'b1 /* verilator lint_on UNUSED */ - // phase selects (mutually exclusive). Encaps adds ST_ENC_H/G (sha3), - // ST_ENC_A (snt), ST_ENC_C (cbd). + // 相位选择(互斥)。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); - // gated output-valid: only the active consumer sees kc_valid_o + // 选通输出有效:只有活跃消费者看到 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; - // input mux: route the active consumer's request to the core + // 输入多路复用:将活跃消费者的请求路由到核心 wire [1599:0] kc_state_i_mux = sel_snt ? snt_kc_state_i : sel_cbd ? cbd_kc_state_i : sha3_kc_state_i; @@ -591,23 +594,23 @@ module mlkem_top #( .ready_o(kc_ready_o), .state_o(kc_state_o), .valid_o(kc_valid_o), - .ready_i(1'b1) // consumers always accept (kc_ready_i=1) + .ready_i(1'b1) // 消费者始终接收 (kc_ready_i=1) ); - // G/H/J share one sha3_top. Single-block (mb_en=0): KeyGen G (ST_G, mode 00), - // Encaps G (ST_ENC_G, mode 11), Decaps D5 G (ST_DEC_G, mode 11). Multi-block - // absorb (mb_en=1): H(ek) (ST_H/ST_ENC_H, SHA3-256 pad) and Decaps D5 J - // (ST_DEC_J, SHAKE256 pad over z||c). mb_* inputs are muxed by phase. + // 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; - // multi-block feed mux: J (ST_DEC_J) drives dj_*, else H drives h_*. + // 多块馈送多路复用: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 (only used when mb_en=0) + .mode(sha3_mode), // G = SHA3-512(仅在 mb_en=0 时使用) .data_i(g_data), .valid_i(sha3_valid), .ready_o(sha3_ready), @@ -619,7 +622,7 @@ module mlkem_top #( .mb_valid_i(mb_valid_mux), .mb_last_i(mb_last_mux), .mb_ready_o(h_mbready), - // shared keccak_core interface (gated by phase in the mux below) + // 共享 keccak_core 接口(在下方的多路复用器中按相位选通) .kc_state_o(kc_state_o), .kc_valid_o(kc_valid_o_sha3), .kc_ready_o(kc_ready_o), @@ -628,55 +631,55 @@ module mlkem_top #( .kc_ready_i(sha3_kc_ready_i) ); - // ---- multi-block H(ek) state (SHA3-256, 6/9/12 blocks); fed to shared u_sha3 ---- - reg [1087:0] h_block_r; // current pre-padded rate block + // ---- 多块 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; // captured H(ek) - reg [3:0] h_blk; // 0..H_NBLK-1 block index (up to 11 for K=4) - reg [7:0] h_byte; // 0..136 byte address being presented (assemble) - reg [1:0] h_phase; // 0=assemble 1=feed 2=wait-perm 3=done - // ek BRAM read is registered (1-cycle latency); assemble presents the - // address for h_byte this cycle and writes the byte that arrived (for the - // address presented last cycle) into h_block_r. Writeback pipeline regs: - reg h_wb_vld; // a byte is arriving this cycle - reg [7:0] h_wb_idx; // its position within the 136-byte block - reg [11:0] h_wb_g; // its global ek byte index - reg [7:0] h_wb_pad; // pad constant to use if g is out of ek range - reg h_wb_inek; // 1 if g is within ek range (use BRAM data) + 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) multi-block SHAKE256 state ---- - // Message = z (32 B, from z_r) || c (ct_bytes_rt B, from c_in_bram). Rate=136. - // SHAKE256 pad: byte at msg_len = 0x1F, last byte of last block |= 0x80. - // Reuses the shared u_sha3 mb_* port (muxed by ST_DEC_J above). - reg [1087:0] dj_block_r; // current pre-padded rate block + // ---- 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; // block index 0..DJ_NBLK-1 (z||c up to ~1600B -> <=12 blks) - reg [7:0] dj_byte; // 0..136 byte being assembled - reg [1:0] dj_phase; // 0=assemble 1=feed 2=wait-perm 3=done + 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; - // writeback pipeline (c_in_bram registered read, 1-cyc latency) + // 写回流水线(c_in_bram 寄存读取,1 周期延迟) reg dj_wb_vld; - reg [7:0] dj_wb_idx; // position within 136-byte block - reg dj_wb_inc; // 1 if global byte g is within c range (use BRAM) - reg dj_wb_inz; // 1 if g < 32 (use z_r byte) - reg [7:0] dj_wb_pad; // pad constant if g out of msg range - reg [4:0] dj_wb_zidx; // z byte index (g) when inz - // J message length = 32 (z) + ct_bytes_rt; total padded blocks. + 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; // last byte of final block + 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; - // global byte index for the address presented this cycle (assemble) + // 本周起呈现的地址的全局字节索引 (组装) wire [11:0] dj_g = {4'd0, dj_blk} * 12'd136 + {4'd0, dj_byte}; - // c_in_bram byte index (when g>=32): g-32 + // c_in_bram 字节索引(当 g>=32 时):g-32 wire [11:0] dj_c_idx = dj_g - 12'd32; - // SHAKE256 pad constant for global byte g + // 全局字节 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 @@ -686,17 +689,17 @@ module mlkem_top #( end endfunction - // h_hash / h_vo are now served by the shared u_sha3 above (mb_en=1 during - // ST_H). They alias the single core's outputs; the H consumer logic below - // already gates on st==ST_H, and u_sha3's valid_o/hash_o are mb-selected. + // 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 over ek (ek_bytes_rt bytes): rate=136. Padded length = h_nblk_rt*136. - // pad: byte ek_bytes_rt = 0x06 (domain + first pad bit), last byte |= 0x80. - // byte b (0..135) of block blk: global g = blk*136 + b. - // ek bytes come from the ek BRAM (registered read); only the pad/zero bytes - // are constants, returned by h_padconst. Reads runtime ek_bytes_rt/h_last_rt. + // 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 @@ -708,20 +711,20 @@ module mlkem_top #( end endfunction - // Global ek byte index for the address currently presented in ST_H assemble. + // ST_H 组装中当前呈现的地址的全局 ek 字节索引。 wire [11:0] h_g_addr = {8'd0, h_blk} * 12'd136 + {4'd0, h_byte}; - // ek BRAM read-address mux: ST_H assemble drives it; otherwise debug readback. - // dbg_dk ek-region takes priority (its loop runs after the ek loop), so the - // single read port serves dbg_byte_o (ek loop) then dbg_dk_o (dk loop). - wire [11:0] dbgdk_ek_off = dbg_dk_idx_i - dk_bytes_rt; // offset within ek region + // 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 load + (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 read-address mux: D2 byteDecode12 (ST_DEC_SDEC) walks dk_pke via - // td_ekaddr (poly*384 + trip*3 + ph); else dbg_byte (sel=1) / dbg_dk. + // 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]; @@ -731,7 +734,7 @@ module mlkem_top #( wire [11:0] snt_coeff; wire snt_vo; wire snt_last; - reg snt_ack; // we accept coeffs + reg snt_ack; // 接收系数 sample_ntt_sync_shared #(.K(KMAX)) u_snt ( .clk(clk), .rst_n(rst_n), @@ -745,7 +748,7 @@ module mlkem_top #( .valid_o(snt_vo), .ready_i(snt_ack), .last_o(snt_last), - // shared keccak_core interface + // 共享 keccak_core 接口 .kc_state_o(kc_state_o), .kc_valid_o(kc_valid_o_snt), .kc_ready_o(kc_ready_o), @@ -757,15 +760,15 @@ module mlkem_top #( // ---- 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-bit signed (two's complement) + wire [11:0] cbd_coeff; // 12 位有符号(二进制补码) wire cbd_vo; wire cbd_last; reg cbd_ack; - // CBD inputs muxed KeyGen vs Encaps: - // KeyGen ST_C: seed=sigma, eta=eta1 (all polys), nonce=c_poly. - // Encaps ST_ENC_C: seed=r, nonce=c_poly; eta = eta1 for y (c_poly=K). nonce sequence 0..2K matches FIPS. + // 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) @@ -781,7 +784,7 @@ module mlkem_top #( .valid_o(cbd_vo), .ready_i(cbd_ack), .last_o(cbd_last), - // shared keccak_core interface + // 共享 keccak_core 接口 .kc_state_o(kc_state_o), .kc_valid_o(kc_valid_o_cbd), .kc_ready_o(kc_ready_o), @@ -790,30 +793,30 @@ module mlkem_top #( .kc_ready_i(cbd_kc_ready_i) ); - // signed (two's complement) -> [0,Q): add Q when negative + // 有符号(二进制补码)-> [0,Q):负数时加 Q wire [11:0] cbd_modq = cbd_coeff[11] ? (cbd_coeff + 12'd3329) : cbd_coeff; - // ---- ntt_core: forward NTT (mode=0, no scaling) of s[i],e[i] in place ---- - // N-stage bookkeeping: process slots S0,S1,E0,E1 (= SLOT_S0 + n_slot). - reg [4:0] n_slot; // 0..2K (process s_hat[0..K-1] then e_hat[0..K-1]) - reg [8:0] n_ridx; // load read-AHEAD pointer 0..256 (leads consume by 1) - reg [7:0] n_widx; // output write index 0..255 - reg n_valid; // feeding coeffs to ntt_core (delayed 1 cyc vs n_ridx) - reg n_loading; // 1 while presenting load addresses to bank_se - reg n_pending; // waiting for ntt_core IDLE to start next slot - wire [SAW-1:0] n_slot_addr = slot_s_rt + n_slot; // s_hat then e_hat contiguous - // NTT slot count: KeyGen processes 2K (s,e); Encaps processes K (y only). + // ---- 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; - // bank_se read addr for the NTT load (relative slot = n_slot); sd_bram - // registers it into bse_rd_data, which feeds ntt_core 1 cycle later. + // 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 inputs muxed: KeyGen/Encaps fwd NTT feeds bse_rd_data (mode 0); - // Encaps E4/E6 INTT sub-phase feeds psum (bt_rd_data) with mode 1. + // 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; @@ -824,204 +827,204 @@ module mlkem_top #( .coeff_in(ntt_in), .valid_i(ntt_vin), .ready_o(ntt_ready), - .mode(ntt_mode), // 0 = fwd (NTT), 1 = inv (INTT, x3303) + .mode(ntt_mode), // 0 = 前向 (NTT), 1 = 逆向 (INTT, x3303) .coeff_out(ntt_coeff), .valid_o(ntt_vo), - .ready_i(1'b1), // always accept output + .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-stage bookkeeping. For each (i,j): LOAD 256 (A,shat) pairs, then accumulate - // 256 products into T_i (init from E_i when j==0, else from running T_i). - reg [2:0] m_i; // row 0..K (needs to reach K to exit) - reg [2:0] m_j; // col 0..K-1 - reg [8:0] m_ld; // load index 0..256 - reg [7:0] m_oidx; // output/accum index 0..255 - reg m_loading; // 1 while streaming pairs into poly_mul - reg m_pending; // wait for poly_mul IDLE before next (i,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) - // ---- Stage 2f: byteEncode12 serializer ---- - // Pack each poly (2 coeffs -> 3 bytes, LSB-first 12-bit). ek = t_hat[0..K-1] - // bytes || rho; dk_pke = s_hat[0..K-1] bytes. Walk coeff pairs per poly. + // ---- 阶段 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 coeff-pair within poly - reg [9:0] e_rho; // 0..31 rho byte copy index (ek tail) - reg e_done; // serialization complete - // source poly slot: t_hat[e_poly] for ek half, s_hat[e_poly-K] for dk half + 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; // index within target - // Registered single-port read (sd_bram timing). One bank read per cycle: - // ek half reads bank_t (t_hat), dk half reads bank_se (s_hat). The two - // coeffs of a pair are serialized across a 4-cycle micro-phase e_ph: - // 0 = fetch c0 - // 1 = c0 ready: write b0, save c0[11:8], fetch c1 - // 2 = c1 ready: write b1, save c1[11:4] - // 3 = write b2, advance pair - reg [1:0] e_ph; // per-pair micro-phase 0..3 - reg [3:0] e_c0_hi; // saved c0[11:8] for b1 - reg [7:0] e_c1_hi; // saved c1[11:4] for b2 + 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}; // bse/bt rd addr in ST_E - // dk half reads bank_se (bse_rd_data), ek half reads bank_t (bt_rd_data); - // both registered inside their sd_bram with the same 1-cycle latency, so - // the coeff for the addr presented last cycle is selected here. + 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 write byte offset within the target memory: pair*3 + byte index. - wire [11:0] e_base = e_pidx * 12'd384; // poly index *384 (=128 pairs*3) + // 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->byte0, ph2->byte1, ph3->byte2 + 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] slot = i*k + j + 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) - // Per row i, three sub-phases (u_sub): - // 0 MAC : sum_j A_hat[j][i] o y_hat[j] (transpose) -> psum bank_t[UPSUM] - // 1 INTT: INTT(psum) mode=1 in place in bank_t[UPSUM] - // 2 ADD : u[i][w] = psum[w] + e1[i][w] mod Q -> bank_se rel (K+i) (over e1) - // y_hat (bank_se 0..K-1) survives for V. Reuses shared u_pmul + u_ntt. + // 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; // bank_t rel slot for the NTT-domain psum - reg [2:0] u_row; // output row i 0..K-1 + 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 bookkeeping (mirrors ST_M) - reg [2:0] u_j; // term col j 0..K-1 - reg [8:0] u_ld; // load read-ahead 0..256 - reg [7:0] u_oidx; // accumulate index 0..255 - reg u_loading; // streaming pairs into poly_mul - reg u_pending; // wait poly_mul IDLE before next j - reg u_j0q; // (u_j==0) delayed 1 cyc (first-term=0 select) - // INTT bookkeeping (mirrors ST_N) - reg [8:0] u_ridx; // INTT load read-ahead 0..256 - reg [7:0] u_widx; // INTT output index 0..255 - reg u_nvalid; // feed psum to ntt_core (mode=1) - reg u_nloading; // presenting INTT load addresses - reg u_npending; // (unused placeholder for symmetry) - // ADD bookkeeping - reg [8:0] u_aidx; // ADD read-ahead 0..256 - reg [7:0] u_awidx; // ADD write index 0..255 - reg u_avalid; // ADD write enable pipeline - // MAC addresses: A^T -> A_hat[u_j][u_row] slot = u_j*k+u_row; y_hat[u_j] rel u_j + // 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 acc addr (MAC) - wire [11:0] u_acc_src = u_j0q ? 12'd0 : bt_rd_data; // first term init 0 + 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 load addr (psum read) + in-place writeback to bank_t[UPSUM] + // 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: read psum (bank_t) + e1 (bank_se K+u_row), write u over e1 (read-ahead 1) + // 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 (lead) - wire [13:0] u_add_uwr = ({2'b0,k_r}+{2'b0,u_row})*256 + u_awidx; // bank_se u (write) + 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). - // Reuses the u_* MAC/INTT/ADD machine with u_row tied to 0 (single output - // poly). Differences from E4: - // - MAC reads t_hat[j] from bank_a slot j*K (== u_aslot=u_j*K, u_row=0), - // so the bank_a MAC address is unchanged. - // - ADD computes psum + e2 + mu (not psum + e1); e2 lives in bank_a slot - // E2_ASLOT (relocated from bank_t[0] in ST_ENC_E2MV), v writes back to - // bank_t[UPSUM] in place. - // - mu[w] = Decompress_1(m bit w) = m_r[w] ? 1665 : 0 (1665 = round(Q/2)). - // u_row_max bounds the row loop: K for U, 1 for V. - localparam E2_ASLOT = 12'd1; // bank_a slot holding relocated e2 (never a t_hat slot, K>=2) + // 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: read psum (bank_t UPSUM) + e2 (bank_a E2_ASLOT) at u_aidx (lead), - // add mu (by write index u_awidx), write v to bank_t[UPSUM] at u_awidx. - wire [13:0] u_v_e2rd = E2_ASLOT*256 + u_aidx[7:0]; // bank_a e2 (lead) - wire [13:0] u_vadd_wr = UPSUM*256 + u_awidx; // bank_t v (write) - wire [11:0] u_mu = m_r[u_awidx] ? 12'd1665 : 12'd0; // mu by msg bit + // 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). - // Reuses the u_* MAC/INTT machine (u_row tied to 0, single poly): - // MAC : s_hat[j] (bank_a slot j*K, == u_aslot with u_row=0) o u_hat[j] - // (bank_se rel j, == u_pm_b_full) -> psum bank_t[UPSUM]. (same - // addressing as Encaps V MAC, which reads t_hat[j] o y_hat[j].) - // INTT: INTT(psum) in place in bank_t[UPSUM]. - // SUB : w[i] = v'[i] - psum[i] mod Q. v' is in bank_a[DEC_VASLOT] (D1), - // psum in bank_t[UPSUM]; read both in parallel (like V-ADD reads - // psum + e2). w written back to bank_t[UPSUM] in place. - wire [13:0] u_w_vrd = DEC_VASLOT*256 + u_aidx[7:0]; // bank_a v' (lead) - wire [13:0] u_wsub_wr = UPSUM*256 + u_awidx; // bank_t w (write) + // 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 iff x in (Q/4, 3Q/4], i.e. - // 832 < x <= 2496 for Q=3329. Pack 256 bits LSB-first into 32 bytes. - // w is read from bank_t[UPSUM] (in place from D3), 1 coeff per 2 cycles. - reg [7:0] men_idx; // coeff 0..255 - reg [1:0] men_ph; // micro-phase + // 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 packs the recovered message bits directly into m_r (reused by D6's - // V/mu re-encrypt and exposed on dbg_mprime_o). + // D4 将恢复出的消息比特直接打包到 m_r 中(被 D6 的 + // V/mu 重加密复用,并在 dbg_mprime_o 上暴露)。 // ================================================================ - // D7: implicit-reject compare (Decaps ST_DEC_CMP). - // Walk all ct bytes, reading c' (ct_bram) and c (c_in_bram) in parallel; - // OR every byte difference into cmp_neq. After the last byte, ss = cmp_neq - // ? K-bar : K'. The walk visits every byte regardless of early differences - // (constant work / no early-out), matching the constant-time spec intent. - // ph0: present both addrs; ph1: compare registered reads, accumulate. - reg [10:0] cmp_idx; // byte index 0..ct_bytes - reg cmp_ph; // 0=present addr, 1=compare - reg cmp_neq; // sticky: any byte differed + // 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; // latched cmp_neq at end (drives ss select) + 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 read addr + 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: copy e2 (bank_t rel slot 0, 256 coeffs) into bank_a[E2_ASLOT]. - // bank_t read leads (em_ridx), bank_a write trails 1 cycle (em_we/em_widx). - reg [8:0] em_ridx; // 0..256 read-ahead over e2 - reg [7:0] em_widx; // bank_a write index - reg em_we; // a coeff is being written this cycle + // 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 rel slot 0 (e2) + 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 -> ciphertext (Encaps ST_ENC_C1/C2). - // Per coeff: read poly coeff -> comp_decomp (mode 0 compress, d=du/dv) -> - // bit-packer (LSB-first) -> emit bytes to ct_bram. c1 = K polys of u - // (d=du), then c2 = 1 poly of v (d=dv). Per poly = 256 coeffs -> 32*d - // bytes (whole), so the bit buffer empties at each poly boundary. - // micro-phase cp_ph: 0 present coeff addr; 1 feed comp_decomp (cd_valid); - // 2 wait pipe; 3 capture compressed + accumulate bits; 4..n drain bytes. + // 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; // coeff presented to comp_decomp - reg cd_valid; // 1-cyc pulse to comp_decomp + reg [11:0] cd_coeff; // 呈现给 comp_decomp 的系数 + reg cd_valid; // 对 comp_decomp 的 1 周期脉冲 wire cd_ready; - wire [11:0] cd_out; // compressed value (low d bits valid) + wire [11:0] cd_out; // 压缩值(低 d 位有效) wire cd_vo; - wire [4:0] cp_d = (st == ST_ENC_C2) ? dv_rt : du_rt; // compress width - // comp_decomp is shared: Encaps C1/C2 compress (mode 0); Decaps DECOMP - // decompresses (mode 1). In DECOMP the decoder feeds dec_dc_coeff/valid/d. + 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=decompress + 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; @@ -1036,68 +1039,66 @@ module mlkem_top #( .valid_o(cd_vo), .ready_i(1'b1) ); - // bit-packer / ct walk bookkeeping - reg [2:0] cp_poly; // c1: 0..K-1 (u rows); c2: single v - reg [7:0] cp_idx; // coeff 0..255 within poly - reg [2:0] cp_ph; // micro-phase - reg [24:0] cp_buf; // bit accumulator (LSB-first) - reg [5:0] cp_nbits; // valid bits in cp_buf - reg [11:0] cp_wa; // ct_bram byte write address (runs c1 then c2) - reg cp_done; // serialization complete (this region) - // coeff source: c1 (ST_ENC_C1) reads u[cp_poly] in bank_se rel (K+cp_poly); - // c2 (ST_ENC_C2) reads v in bank_t rel slot UPSUM (single poly, cp_poly=0). + // 位打包器 / 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) - // packer generalization (E5 c1 vs E7 c2): - // coeff source: c1 = bank_se (u), c2 = bank_t (v) - // poly count: c1 = K (u rows), c2 = 1 (single v) - // bit width cp_d already = dv_rt for C2 else du_rt (declared above). + // 打包器泛化(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 + Decompress (decrypt c1/c2 -> u'/v'). - // Reverse of the C1/C2 packer: walk c_in_bram bytes, accumulate LSB-first - // into a bit buffer, extract d-bit symbols, feed comp_decomp (mode=1 - // decompress), and write each result (mod q) to a bank. - // c1 = K polys, d=du -> u'[i] in bank_se rel i (0..K-1) - // c2 = 1 poly, d=dv -> v' in bank_t rel slot DEC_VSLOT - // c1 = K polys, d=du -> u'[i] in bank_se rel i (0..K-1) - // c2 = 1 poly, d=dv -> v' in bank_a slot DEC_VASLOT (so D3's w-SUB can - // read psum (bank_t) and v' (bank_a) in parallel, like Encaps V-ADD). - // micro-phase dec_ph: - // 0 present c_in byte addr; 1 capture byte, append 8 bits to buf; - // while (nbits>=d): extract d-bit symbol -> comp_decomp (decompress); - // 2 wait pipe; 3 cd_vo -> write coeff to bank, advance coeff index. + // 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; // bank_a slot for v' (free: s_hat at j*K, slot 1 unused K>=2) - reg [2:0] dec_poly; // c1: 0..K-1; c2: single (=K marker) - reg [7:0] dec_cidx; // coeff 0..255 within poly (feed side) - reg [7:0] dec_widx; // coeff 0..255 within poly (writeback side, lags pipe) - reg [1:0] dec_ph; // micro-phase - reg [11:0] dec_ba; // c_in_bram byte read address (c1 then c2) - reg [24:0] dec_buf; // bit accumulator (LSB-first) - reg [5:0] dec_nbits; // valid bits in dec_buf - reg dec_dc_done; // D1 complete (both c1 and c2 decoded) - reg dec_in_c2; // 0 = decoding c1 (u'), 1 = decoding c2 (v') - // comp_decomp feed (decompress): the extracted d-bit symbol. + 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 uses dv, c1 uses du - // (c_in_bram read addr driven by cin_rd_addr_r, set to dec_ba in the walker) + 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] in bank_a (abs slot m_aslot). pm_b: s_hat[j] in - // bank_se (relative slot = m_sslot - slot_s_rt = m_j). m_ld is a read-ahead - // pointer; both bank reads come from their sd_bram (registered, 1-cycle - // latency) and feed poly_mul one cycle later (pm_valid delayed 1 cyc). + // 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 registered read - wire [11:0] pm_b_in = bse_rd_data; // bank_se sd_bram registered read (load phase) + 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), @@ -1110,22 +1111,22 @@ module mlkem_top #( .ready_i(1'b1) ); - // accumulator source: e_hat[i] for first term (j==0), else running t_hat[i]. - // e_hat[i] lives in bank_se at relative slot (slot_e_rt-slot_s_rt + m_i) = K+m_i. - // t_hat[i] lives in bank_t at relative slot m_i. Both reads come from their - // sd_bram (bse_rd_data / bt_rd_data) with the same 1-cycle latency. - // Registered read-ahead: present the index the NEXT pm_vo will consume + // 累加器来源:首项时 (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 - // The j-select is applied on the registered outputs (m_jq = (m_j==0) - // delayed 1 cyc to align with the read latency). RMW read-old holds: read - // addr (m_oidx+1) leads write addr (m_oidx). Cadence CALC/C0/C1. + // 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 in acc) + 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) delayed 1 cyc to match read latency - // selected accumulator source aligned with pm_coeff + 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 (both < Q, sum < 2Q): one conditional subtract + // (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]; @@ -1134,23 +1135,23 @@ module mlkem_top #( 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: settle after dk/c parse, then D1 Decompress. D1 lands in DONE - // once u'/v' are computed so the stage can be dbg-checked. + // 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 decode (reuse TDEC machine), then u_hat = NTT(u'). D2 - // lands in DONE once u_hat is ready so the stage can be dbg-checked. + // 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]). Single output poly - // (u_row 0..0); MAC->INTT->SUB, then D4 encodes m'. + // 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) single-block, then K-bar = J(z||c) multi-block. + // D5: (K',r') = G(m'||h) 单块,然后 K-bar = J(z||c) 多块。 ST_DEC_G: if (sha3_vo) st_next = ST_DEC_J; - // D5 J done -> D6 re-encrypt: c' = K-PKE.Encrypt(ek_pke, m', r'). - // Reuse the entire Encaps pipeline (rho load -> A -> C -> ... -> C2). - // r' is in r_r (CBD seed), m' in m_r (V/mu), ek_pke in ek_bram. + // 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; @@ -1161,19 +1162,19 @@ module mlkem_top #( 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) captured - ST_ENC_LOAD: if (rl_idx >= 6'd33) st_next = ST_ENC_A; // rho loaded + 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 polys done - ST_ENC_N: if (n_slot >= {2'b0, k_r}) st_next = ST_ENC_U; // K slots (y_hat) - ST_ENC_U: if (u_row >= k_r) st_next = ST_ENC_C1; // u[0..K-1] done - ST_ENC_C1: if (cp_done) st_next = ST_ENC_TDEC; // E5 done -> E6 - ST_ENC_TDEC: if (td_done) st_next = ST_ENC_E2MV; // t_hat decoded -> relocate e2 - ST_ENC_E2MV: if (em_done) st_next = ST_ENC_V; // e2 relocated -> compute v - ST_ENC_V: if (u_row >= 3'd1) st_next = ST_ENC_C2; // E6: v done -> E7 + 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: walk ct bytes comparing c' (ct_bram) vs c (c_in_bram); when the - // last byte is compared, select ss = (c'==c) ? K' : K-bar and finish. + // 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; @@ -1323,57 +1324,57 @@ module mlkem_top #( end else begin st <= st_next; - // BRAM write-enables default low; pulsed where a byte is written. + // BRAM write-enables 默认低;写入字节时脉冲为高。 ek_we <= 1'b0; dkp_we <= 1'b0; - td_we <= 1'b0; // TDEC bank_a write default low - ct_we <= 1'b0; // ct_bram byte write default low (E5/E7) - em_we <= 1'b0; // e2-relocate bank_a write default low (E6) + td_we <= 1'b0; // TDEC bank_a 写入默认低 + ct_we <= 1'b0; // ct_bram 字节写入默认低 (E5/E7) + em_we <= 1'b0; // e2 搬迁 bank_a 写入默认低 (E6) - // Kick off when entering from IDLE: KeyGen starts G; Encaps captures - // op/m and arms the H(ek) machinery (ST_ENC_H reuses the ST_H FSM); - // Decaps captures op (dk/c already streamed; z/h captured at load). + // 从 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; // capture runtime ML-KEM param + k_r <= k_i; // 捕获运行时 ML-KEM 参数 op_r <= op_i; if (op_i == 2'd1) begin - m_r <= msg_i; // capture Encaps message - // arm H(ek) (same fields the ST_E->ST_H arming sets) + m_r <= msg_i; // 捕获 Encaps 消息 + // 武装 H(ek)(与 ST_E->ST_H 武装设置的字段相同) h_blk <= 3'd0; h_byte <= 8'd0; - h_phase <= 2'd0; // assemble + h_phase <= 2'd0; // 组装 h_mbvalid<= 1'b0; h_mblast <= 1'b0; - h_ack <= 1'b1; // ready to consume final digest + h_ack <= 1'b1; // 准备好消费最终摘要 h_wb_vld <= 1'b0; end else if (op_i == 2'd2) begin - // Decaps: dk_pke/ek_pke already in BRAM; z/H(ek) captured into - // z_r/hek_r during load (below). Nothing else to arm in D0. + // 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 load: capture the H(ek) and z byte regions into registers - // as they stream in (the dk_pke/ek_pke regions go to BRAM via the - // write muxes). Byte i within a region lands in [8i +: 8]. Uses the - // LIVE k_i boundaries (k_r not yet captured during preload). + // 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 - // Drop valid once accepted + // valid 被接受后撤销 if (sha3_valid && sha3_ready) sha3_valid <= 1'b0; - // Capture rho/sigma when G completes; arm A stage + // G 完成时捕获 rho/sigma;武装 A 阶段 if (st == ST_G && sha3_vo) begin - rho_r <= sha3_hash[255:0]; // rho = G output bytes 0..31 - sigma_r <= sha3_hash[511:256]; // sigma = bytes 32..63 + 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; // start first SampleNTT + snt_valid <= 1'b1; // 启动第一个 SampleNTT snt_ack <= 1'b1; a_pair <= 5'd0; a_i <= 3'd0; @@ -1382,21 +1383,21 @@ module mlkem_top #( a_busy <= 1'b0; end - // ---- ST_A / ST_ENC_A: drive SampleNTT, store 256 coeffs per pair ---- + // ---- ST_A / ST_ENC_A: 驱动 SampleNTT, 每对存储 256 个系数 ---- if (st == ST_A || st == ST_ENC_A) begin - // mark busy once this pair's request accepted + // 该对的请求被接受后标记忙碌 if (snt_valid && snt_ready) begin snt_valid <= 1'b0; a_busy <= 1'b1; end - // store each output coefficient only while busy (ignore stale - // last coeff from prior poly). The bank_a write itself is the - // combinational ba_we/ba_wa/ba_wd assigns above; here we only - // advance the write index and (i,j) bookkeeping. + // 仅在忙碌时存储每个输出系数(忽略前一个多项式的 + // 过期尾系数)。bank_a 写入本身由上面的组合逻辑 + // ba_we/ba_wa/ba_wd assign 完成;这里我们只推进 + // 写入索引和 (i,j) 簿记。 if (a_busy && snt_vo && snt_ack) begin if (snt_last) begin - // finished this poly; advance (i,j) in row-major order + // 完成此多项式;按行主序推进 (i,j) a_pair <= a_pair + 5'd1; a_widx <= 8'd0; a_busy <= 1'b0; @@ -1406,7 +1407,7 @@ module mlkem_top #( a_j <= 3'd0; a_i <= a_i + 3'd1; end - // start next SampleNTT if more pairs remain + // 如果还有更多对,启动下一个 SampleNTT if (a_pair + 5'd1 < kk_rt) snt_valid <= 1'b1; end else begin a_widx <= a_widx + 8'd1; @@ -1414,7 +1415,7 @@ module mlkem_top #( end end - // Arm C stage when A finishes (KeyGen ST_A or Encaps ST_ENC_A) + // 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; @@ -1424,9 +1425,9 @@ module mlkem_top #( c_busy <= 1'b0; end - // ---- ST_C / ST_ENC_C: drive CBD, store 256 mod-q coeffs per poly ---- - // KeyGen: 2K polys (s,e). Encaps: 2K+1 polys (y,e1,e2). Loop bound - // differs: KeyGen restarts while c_poly+1 < 2K; Encaps while < 2K+1. + // ---- 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; @@ -1438,7 +1439,7 @@ module mlkem_top #( c_poly <= c_poly + 3'd1; c_widx <= 8'd0; c_busy <= 1'b0; - // restart for next poly while more remain (state-dependent bound) + // 当还有更多多项式时重启下一个(状态相关边界) if (st == ST_ENC_C) begin if (c_poly + 3'd1 < {k_r, 1'b1}) cbd_valid <= 1'b1; // < 2K+1 end else begin @@ -1450,9 +1451,9 @@ module mlkem_top #( end end - // Arm N stage when C finishes: prime load of slot S0. n_ridx is a - // read-ahead pointer; bank_se read is registered inside sd_bram (bse_rd_data) - // and fed to ntt_core one cycle later, so valid starts low (priming). + // 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 @@ -1460,43 +1461,43 @@ module mlkem_top #( n_ridx <= 9'd0; n_widx <= 8'd0; n_valid <= 1'b0; - n_loading <= 1'b1; // begin presenting load addresses + n_loading <= 1'b1; // 开始呈现加载地址 n_pending <= 1'b0; end - // ---- ST_N / ST_ENC_N / ST_DEC_NTT: forward NTT in place. KeyGen: 2K - // slots (s,e). Encaps: K slots (y). Decaps D2: K slots (u' -> u_hat). ---- + // ---- 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 - // slot-count bound: 2K for KeyGen, K for Encaps - // (n_slot_max below); same LOAD/OUTPUT cadence either way. + // 槽位计数边界:KeyGen 为 2K,Encaps 为 K + //(见下面 n_slot_max);两种方式的 LOAD/OUTPUT 节拍相同。 if (n_loading) begin if (n_ridx == 9'd256) begin - // 256th coeff consumed this cycle; stop presenting addr + // 本周起已消耗第 256 个系数;停止呈现地址 n_loading <= 1'b0; n_valid <= 1'b0; end else begin n_ridx <= n_ridx + 9'd1; - n_valid <= 1'b1; // data presented last cycle is valid + n_valid <= 1'b1; // 上一周期呈现的数据有效 end end - // OUTPUT phase: collect 256 results, write back to same slot. + // OUTPUT 阶段:收集 256 个结果,写回相同槽位。 if (ntt_vo) begin - n_widx <= n_widx + 8'd1; // wraps 255->0 after last + n_widx <= n_widx + 8'd1; // 最后之后 255->0 回绕 end - // Slot complete when ntt_core returns to DONE + // 当 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; // wait one cycle for core IDLE + n_pending <= 1'b1; // 等待一个周期让 core 进入 IDLE end else begin - n_slot <= n_slot + 3'd1; // == n_slot_max -> exit + n_slot <= n_slot + 3'd1; // == n_slot_max -> 退出 end end - // Kick next slot's load once core is back IDLE (re-prime) + // core 回到 IDLE 后启动下一个槽位的加载(重新启动) if (n_pending && ntt_ready && !ntt_done) begin n_ridx <= 9'd0; n_valid <= 1'b0; @@ -1505,9 +1506,9 @@ module mlkem_top #( end end - // Arm M stage when N finishes: prime first (i=0,j=0) poly_mul load. - // m_ld read-ahead pointer; bank_a/bank_se sd_bram reads land 1 cyc - // later, pm_valid asserted one cycle after an address is presented. + // 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; @@ -1520,40 +1521,40 @@ module mlkem_top #( // ---- ST_M: t_hat[i] = e_hat[i] + sum_j A[i][j] o s_hat[j] ---- if (st == ST_M) begin - // accumulator reads come from sd_bram (bse_rd_data e_hat / - // bt_rd_data t_hat). m_jq aligns the j-select with the 1-cycle - // read latency. (bse_rd_addr muxes load vs acc by m_loading.) + // 累加器读取来自 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: present read-ahead addr to bank_a/bank_se via their - // sd_bram read ports (ba_rd_addr=pm_a_full, bse_rd_addr=pm_b_full - // while m_loading); ba_rd_data/bse_rd_data land next cycle and - // are consumed by poly_mul (pm_valid). poly_mul holds ready high - // through LOAD, so a fixed 1-cycle skew suffices. + // 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; // 256th pair consumed this cycle + 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; // pair presented last cycle is valid + pm_valid <= 1'b1; // 上一周期呈现的系数对有效 end end - // ACCUMULATE: each product coeff += e_hat (j==0) or running t_hat. - // The bank_t write is the combinational bt_we/bt_wa/bt_wd assigns - // below; here we only advance the accumulate index / (i,j). + // 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 - // finished this (i,j) term; advance + // 完成此 (i,j) 项;推进 if (m_j + 2'd1 < k_r) begin m_j <= m_j + 2'd1; - m_pending <= 1'b1; // next term, same row + m_pending <= 1'b1; // 下一个项,同一行 end else begin m_j <= 2'd0; - m_i <= m_i + 2'd1; // next row (or == K -> DONE) + m_i <= m_i + 2'd1; // 下一行(或 == K -> DONE) if (m_i + 2'd1 < k_r) m_pending <= 1'b1; end end else begin @@ -1561,7 +1562,7 @@ module mlkem_top #( end end - // Start next (i,j) poly_mul load once core is IDLE again (re-prime) + // core 再次进入 IDLE 后启动下一个 (i,j) poly_mul 加载(重新启动) if (m_pending && pm_ready && !pm_vo) begin m_loading <= 1'b1; m_ld <= 9'd0; @@ -1571,7 +1572,7 @@ module mlkem_top #( end end - // Arm Encaps U stage when N finishes: prime first row MAC (i=0,j=0). + // 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 @@ -1583,10 +1584,10 @@ module mlkem_top #( pm_valid <= 1'b0; end - // ---- ST_ENC_U/V sub-phase 0: MAC sum_j (A^T or t_hat)[j] o y_hat[j] ---- - // psum (init 0 at j==0) accumulates into bank_t[UPSUM]. Mirrors ST_M - // load/accumulate cadence (read-ahead by 1, j-select via u_j0q). - // 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). + // ---- 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); @@ -1603,13 +1604,13 @@ module mlkem_top #( end if (pm_vo) begin - // bank_t psum write is combinational (u_psum_we); advance idx + // 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; // next term, same row + u_pending <= 1'b1; // 下一个项,同一行 end else begin - // row's MAC done -> INTT sub-phase + // 行的 MAC 完成 -> INTT 子阶段 u_sub <= 2'd1; u_ridx <= 9'd0; u_widx <= 8'd0; @@ -1621,7 +1622,7 @@ module mlkem_top #( end end - // re-prime next term's poly_mul load + // 重新启动下一个项的 poly_mul 加载 if (u_pending && pm_ready && !pm_vo) begin u_loading <= 1'b1; u_ld <= 9'd0; @@ -1631,7 +1632,7 @@ module mlkem_top #( end end - // ---- ST_ENC_U/V sub-phase 1: INTT(psum) mode=1 in place (bank_t) ---- + // ---- 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 @@ -1642,9 +1643,9 @@ module mlkem_top #( u_nvalid <= 1'b1; end end - if (ntt_vo) u_widx <= u_widx + 8'd1; // in-place write (u_intt_we) + if (ntt_vo) u_widx <= u_widx + 8'd1; // 原地写入 (u_intt_we) if (ntt_done) begin - // INTT done -> ADD sub-phase (psum + e1[u_row]) + // INTT 完成 -> ADD 子阶段(psum + e1[u_row]) u_sub <= 2'd2; u_aidx <= 9'd0; u_awidx <= 8'd0; @@ -1652,27 +1653,27 @@ module mlkem_top #( end end - // ---- ST_ENC_U/V + ST_DEC_W sub-phase 2: ADD/SUB + writeback ---- - // 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). - // Read psum (bank_t) + e1/e2/v' at u_aidx; both arrive 1 cyc later, so - // register (valid,widx) and write next cycle. u_row_max bounds the - // row loop (K for U, 1 for V/D3). + // ---- 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; // addr presented this cyc -> write next + u_avalid <= 1'b1; // 本周起地址已呈现 -> 下周起写入 u_awidx <= u_aidx[7:0]; end else begin - u_avalid <= 1'b0; // no more addresses + u_avalid <= 1'b0; // 没有更多地址 end - // writeback (u_add_we / u_v_we) commits index u_awidx this cycle. - // Advance row after the 256th coeff (u_awidx==255) is written. + // 写回(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; // next row MAC + u_sub <= 2'd0; // 下一行 MAC u_j <= 3'd0; u_ld <= 9'd0; u_oidx <= 8'd0; @@ -1685,8 +1686,8 @@ module mlkem_top #( end end - // Arm E5 (ST_ENC_C1) when U finishes: c1 = byteEncode_du(Compress_du(u)). - // Walk K polys * 256 coeffs; reset bit-packer + ct write pointer. + // 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; @@ -1698,37 +1699,37 @@ module mlkem_top #( cd_valid <= 1'b0; end - // ---- ST_ENC_C1/C2: Compress_d -> byteEncode_d -> ct region ---- - // C1 (E5): Compress_du(u[0..K-1]) from bank_se -> ct[0..c1_bytes). - // C2 (E7): Compress_dv(v) from bank_t[UPSUM] -> ct[c1_bytes..ct_bytes). - // Per coeff, 5-phase micro-sequence (read-ahead 1 cyc bram + 1 cyc - // comp_decomp pipe), then a drain sub-phase emitting whole bytes: - // ph0: present coeff addr (cp_se_full / cp_bt_full by state). - // ph1: coeff arrives (cp_coeff_src) -> latch into cd_coeff, pulse cd_valid. - // ph2: drop cd_valid (1-cyc pulse); comp_decomp captures. - // ph3: cd_vo high -> cd_out (low cp_d bits) valid; append LSB-first. - // ph4: drain: while >=8 bits buffered, emit one ct byte/cycle; then advance. - // Each poly = 256 coeffs = 32*d bytes (whole), so cp_buf empties at - // each poly boundary (no carry across polys / regions). + // ---- 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; // addr presented; wait read + 3'd0: cp_ph <= 3'd1; // 地址已呈现;等待读取 3'd1: begin - cd_coeff <= cp_coeff_src; // u (bank_se) or v (bank_t) - cd_valid <= 1'b1; // feed comp_decomp (1-cyc pulse) + 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 captured this cyc + cd_valid <= 1'b0; // 本周起 comp_decomp 已捕获 cp_ph <= 3'd3; end 3'd3: begin - // cd_out valid (cd_vo): append cp_d bits LSB-first at bit cp_nbits + // 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: drain whole bytes + default: begin // 3'd4: 排空整字节 if (cp_nbits >= 6'd8) begin ct_we <= 1'b1; ct_wa <= cp_wa; @@ -1737,11 +1738,11 @@ module mlkem_top #( cp_buf <= cp_buf >> 8; cp_nbits <= cp_nbits - 6'd8; end else begin - // coeff fully packed; advance coeff / poly + // 系数完全打包;推进系数 / 多项式 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; // region complete + else cp_done <= 1'b1; // 区域完成 end else begin cp_idx <= cp_idx + 8'd1; end @@ -1751,10 +1752,10 @@ module mlkem_top #( endcase end - // Arm E7 (ST_ENC_C2) when V finishes: c2 = byteEncode_dv(Compress_dv(v)). - // Single poly (v at bank_t UPSUM); ct write pointer cp_wa CONTINUES - // from c1_bytes (NOT reset) so c2 lands right after c1. cp_buf/nbits - // are 0 here (c1 ended on a poly/byte boundary) but reset for safety. + // 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; @@ -1763,10 +1764,10 @@ module mlkem_top #( cp_nbits <= 6'd0; cp_done <= 1'b0; cd_valid <= 1'b0; - // cp_wa intentionally preserved (= c1_bytes_rt from C1). + // cp_wa 有意保留(= 来自 C1 的 c1_bytes_rt)。 end - // Arm D1 DECOMP when load settles: decode c1 (u') first. + // 加载稳定后武装 D1 DECOMP:先解码 c1 (u')。 if (st == ST_DEC_LOAD && st_next == ST_DEC_DECOMP) begin dec_poly <= 3'd0; dec_cidx <= 8'd0; @@ -1778,31 +1779,31 @@ module mlkem_top #( dec_in_c2 <= 1'b0; dec_dc_valid <= 1'b0; dec_dc_done <= 1'b0; - cin_rd_addr_r<= 11'd0; // present byte 0 address + cin_rd_addr_r<= 11'd0; // 呈现字节 0 地址 end - // ---- ST_DEC_DECOMP (D1): byteDecode_d + Decompress c1/c2 ---- - // Reverse of the C1/C2 packer. Per coeff: - // ph0: if nbits ph1; - // else extract low d bits -> comp_decomp (decompress) -> ph2. - // ph1: append cin_rd_data (8 bits) at dec_nbits; advance dec_ba; - // present next byte addr; back to ph0. - // ph2: drop dc_valid (pulse captured) -> ph3. - // ph3: cd_vo -> dec_u_we/dec_v_we writes cd_out; advance coeff. - // c1 = K polys (d=du) -> u'[poly] bank_se; then c2 = 1 poly (d=dv) - // -> v' bank_a[DEC_VASLOT]. Byte stream is contiguous in c_in_bram. + // ---- 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 - // enough bits: extract low d as the decoded symbol + 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 - // need another byte (cin_rd_data reflects dec_ba) + // 需要另一个字节(cin_rd_data 反映 dec_ba) dec_ph <= 2'd1; end end @@ -1810,29 +1811,29 @@ module mlkem_top #( 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; // present next byte + 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 captured + dec_dc_valid <= 1'b0; // comp_decomp 已捕获 dec_ph <= 2'd3; end - default: begin // 2'd3: capture cd_vo + default: begin // 2'd3: 捕获 cd_vo if (cd_vo) begin - // dec_u_we/dec_v_we commit cd_out at dec_widx this cycle. + // 本周起 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; // next u' row + dec_poly <= dec_poly + 3'd1; // 下一行 u' end else begin - dec_in_c2 <= 1'b1; // switch to c2 (v') + dec_in_c2 <= 1'b1; // 切换到 c2 (v') dec_poly <= 3'd0; end end else begin - dec_dc_done <= 1'b1; // v' done -> D1 complete + dec_dc_done <= 1'b1; // v' 完成 -> D1 完成 end end else begin dec_cidx <= dec_cidx + 8'd1; @@ -1843,25 +1844,24 @@ module mlkem_top #( endcase end - // Arm E stage when M finishes + // M 完成时武装 E 阶段 if (st == ST_M && st_next == ST_E) begin e_poly <= 3'd0; e_pair <= 8'd0; - e_ph <= 2'd0; // start at fetch-c0 of first pair + e_ph <= 2'd0; // 从第一对系数的取回-c0 开始 e_rho <= 10'd0; e_done <= 1'b0; end // ---- ST_E: byteEncode12 t_hat -> ek, s_hat -> dk_pke ---- - // Single registered bank read per cycle; 4-cycle micro-phase per - // coeff pair (ph0 fetch c0, ph1 write b0 + fetch c1, ph2 write b1, - // ph3 write b2). The coeff for the addr presented last cycle is - // e_rd_coeff (= bse_rd_data for dk-half, bt_rd_data for ek-half), - // both registered inside their sd_bram (bse_rd_addr/bt_rd_addr = - // e_rd_full in ST_E). + // 每个系数对单周期寄存 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: fetch only (prime). ph1..3: write one packed byte. + // ph0: 仅取回(启动)。ph1..3: 写入一个打包字节。 if (e_ph != 2'd0) begin if (!e_is_dk) begin ek_we <= 1'b1; @@ -1873,16 +1873,16 @@ module mlkem_top #( dkp_wd <= e_wbyte; end end - // save coeff high nibbles as they become available + // 系数高半字节可用时保存 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] - // advance micro-phase / pair / poly + // 推进微相 / 系数对 / 多项式 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; // next poly or -> rho phase + e_poly <= e_poly + 5'd1; // 下一个多项式 或 -> rho 阶段 end else begin e_pair <= e_pair + 8'd1; end @@ -1890,7 +1890,7 @@ module mlkem_top #( e_ph <= e_ph + 2'd1; end end else begin - // rho copy: ek[384*K + r] = rho byte r (r = 0..31), 1 byte/cycle + // 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]; @@ -1899,34 +1899,33 @@ module mlkem_top #( end end - // Arm H stage when E finishes + // E 完成时武装 H 阶段 if (st == ST_E && st_next == ST_H) begin h_blk <= 3'd0; h_byte <= 8'd0; - h_phase <= 2'd0; // assemble + h_phase <= 2'd0; // 组装 h_mbvalid<= 1'b0; h_mblast <= 1'b0; - h_ack <= 1'b1; // ready to consume final digest - h_wb_vld <= 1'b0; // no pending writeback yet + h_ack <= 1'b1; // 准备好消费最终摘要 + h_wb_vld <= 1'b0; // 没有待处理的写回 end - // ---- ST_H / ST_ENC_H: H(ek) via multi-block SHA3-256 ---- - // Same logic for KeyGen (ek just written by ST_E) and Encaps (ek - // preloaded into ek_bram by the TB). hek_r captures H(ek) either way. + // ---- 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) - // assemble 136 bytes of block h_blk into h_block_r. - // ek BRAM read is registered: present addr for h_byte this - // cycle, write back the byte that arrived for the addr we - // presented last cycle (h_wb_*). h_byte runs 0..136 (one - // extra cycle to flush the final writeback). + // 将块 h_blk 的 136 个字节组装到 h_block_r 中。 + // ek BRAM 读取是寄存的:本周起呈现 h_byte 的地址, + // 将上一周期呈现地址对应的到达字节写回(h_wb_*)。 + // h_byte 运行 0..136(额外一个周期以刷新最终写回)。 2'd0: begin - // writeback the byte read for the previous address + // 写回上一地址读取的字节 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 - // set up writeback for the address presented this cycle + // 为本周起呈现的地址设置写回 h_wb_vld <= 1'b1; h_wb_idx <= h_byte; h_wb_g <= h_g_addr; @@ -1934,65 +1933,65 @@ module mlkem_top #( h_wb_pad <= h_padconst(h_blk, h_byte); h_byte <= h_byte + 8'd1; end else begin - // h_byte==136: final writeback (for byte 135) done above + // 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; // feed + h_phase <= 2'd1; // 馈送 end end - // feed: hold valid until accepted (mb_ready drops) + // 馈送: 保持 valid 直到被接受(mb_ready 撤销) 2'd1: begin if (h_mbvalid && !h_mbready) begin h_mbvalid <= 1'b0; h_mblast <= 1'b0; - h_phase <= 2'd2; // wait permute + h_phase <= 2'd2; // 等待置换 end end - // wait permute done: ready again (more blocks) or digest valid (last) + // 等待置换完成:再次就绪(更多块)或摘要有效(最后一块) 2'd2: begin if (h_vo) begin hek_r <= h_hash[255:0]; - h_phase <= 2'd3; // done + h_phase <= 2'd3; // 完成 end else if (h_mbready) begin h_blk <= h_blk + 3'd1; - h_phase <= 2'd0; // assemble next block + h_phase <= 2'd0; // 组装下一个块 end end - default: ; // 2'd3 done: hold + default: ; // 2'd3 完成: 保持 endcase end - // Arm Encaps G when H(ek) finishes: fire the 64-byte single-block - // G(m||H(ek)). hek_r now holds H(ek); enc_g_data = {hek_r, m_r}. + // 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 - // Capture (K, r) when Encaps G completes. ss = K = low half, r = high. + // Encaps G 完成时捕获 (K, r)。ss = K = 低半部分,r = 高半部分。 if (st == ST_ENC_G && sha3_vo) begin - ss_r <= sha3_hash[255:0]; // K (shared secret) = G bytes 0..31 - r_r <= sha3_hash[511:256]; // r = G bytes 32..63 + 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 - // Arm Decaps D5 G when m' is ready (ST_DEC_MENC -> ST_DEC_G): fire the - // 64-byte single-block G(m'||h). dec_g_data = {hek_r, m_r}. + // 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 - // Capture (K', r') when D5 G completes. K' = low half (candidate ss), - // r' = high half (PRF seed for D6 re-encrypt). Reuse ss_r / r_r. + // 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 bytes 0..31 - r_r <= sha3_hash[511:256]; // r' = G bytes 32..63 + 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 - // Arm D5 J(z||c) when G completes (ST_DEC_G -> ST_DEC_J): assemble the - // first 136-byte block. dj_ack high to consume the final digest. + // 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; @@ -2002,20 +2001,20 @@ module mlkem_top #( dj_ack <= 1'b1; dj_done <= 1'b0; dj_wb_vld <= 1'b0; - cin_rd_addr_r <= 11'd0; // present c byte 0 (g=32 -> c_idx 0) + cin_rd_addr_r <= 11'd0; // 呈现 c 字节 0(g=32 -> c_idx 0) end - // ---- ST_DEC_J: K-bar = J(z||c) multi-block SHAKE256 ---- - // Mirror of the H(ek) multi-block machine. Byte source by global g: - // g < 32 -> z_r byte g - // 32 <= g < msglen -> c_in_bram byte (g-32), registered read - // else -> SHAKE256 pad constant - // c_in_bram read is registered: present c_idx for dj_byte this cycle, - // write back the byte that arrived for the addr presented last cycle. + // ---- 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 - // writeback the byte read for the previous address + // 写回上一地址读取的字节 if (dj_wb_vld) begin if (dj_wb_inz) dj_block_r[dj_wb_idx*8 +: 8] <= z_r[dj_wb_zidx*8 +: 8]; @@ -2031,9 +2030,9 @@ module mlkem_top #( 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 addr is presented combinationally (cin_rd_addr - // mux uses dj_c_idx during ST_DEC_J); data lands next - // cycle, matching this byte's writeback. + // 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; @@ -2060,11 +2059,11 @@ module mlkem_top #( dj_phase <= 2'd0; end end - default: ; // done + default: ; // 完成 endcase end - // Arm D7 compare when re-encrypt finishes (ST_ENC_C2 -> ST_DEC_CMP). + // 重加密完成时武装 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; @@ -2072,18 +2071,18 @@ module mlkem_top #( cmp_done <= 1'b0; end - // ---- ST_DEC_CMP (D7): constant-time c' == c compare + ss select ---- - // ph0: present cmp_idx to both ct_bram (c') and c_in_bram (c). - // ph1: registered reads valid -> OR any difference into cmp_neq, - // advance. After the last byte, latch dec_reject and ss stays - // K' (ss_r) or switches to K-bar (kbar_r) via the ss_o mux. + // ---- 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; // addr presented; wait for read + 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; // include final byte + dec_reject <= cmp_neq | cmp_byte_neq; // 包含最终字节 cmp_done <= 1'b1; end else begin cmp_idx <= cmp_idx + 11'd1; @@ -2099,17 +2098,17 @@ module mlkem_top #( rl_vld <= 1'b0; end - // ---- ST_ENC_LOAD: stream 32 rho bytes from ek_bram into rho_r ---- - // ek read is registered (1-cyc latency): the data arriving this cycle - // is for the address presented last cycle (rl_idx-1). Present addr - // rl_idx (valid 0..31); write rho_r[rl_idx-1] when rl_idx in 1..32. + // ---- 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; // exit when rl_idx >= 33 + rl_idx <= rl_idx + 6'd1; // 当 rl_idx >= 33 时退出 end - // Arm ST_ENC_A (regenerate A_hat via SampleNTT, same as ST_A). + // 武装 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; @@ -2120,17 +2119,17 @@ module mlkem_top #( a_busy <= 1'b0; end - // Arm ST_ENC_TDEC (byteDecode12: ek -> t_hat in bank_a). Now follows - // E5 (ST_ENC_C1) since e2 occupied bank_t during C/N/U and t_hat is - // only needed for V. (Was armed off ST_ENC_A in the E1 scaffold.) + // 武装 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 - // Arm D2 s_hat decode (ST_DEC_SDEC) when DECOMP finishes: same TDEC - // machine, byteDecode12 dk_pke -> s_hat in bank_a slot j*K. + // 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; @@ -2138,16 +2137,16 @@ module mlkem_top #( td_done <= 1'b0; end - // Encaps: ek -> t_hat. Decaps D2: dk_pke -> s_hat. Same 5-cycle - // micro-phase per triple; only the byte source (td_byte) differs. + // 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 - // capture the byte that arrived for the address presented last cycle + // 捕获上一周期呈现地址对应的到达字节 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; - // write decoded coeffs into bank_a at slot td_poly*K (so V's MAC - // reads t_hat[j] via the same u_aslot=u_j*K addressing, u_row=0). + // 将解码系数写入 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 coeffs ---- - // Present read addr em_ridx (bank_t rel 0); bank_t read is registered - // so bt_rd_data next cycle = e2[em_ridx]. Schedule the bank_a write - // (em_we/em_widx) for that next cycle with em_widx == em_ridx, so the - // write commits e2[R] into slot[R] (no off-by-one). + // ---- 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 // presenting a valid e2 addr this cycle - em_we <= 1'b1; // -> write next cycle (ba_wd = bt_rd_data) + 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; // last write (e2[255]) issued + if (em_ridx == 9'd256) em_done <= 1'b1; // 最后写入(e2[255])已发出 else em_ridx <= em_ridx + 9'd1; end - // Arm ST_ENC_V when e2 relocated: prime first (only) row MAC (i=0,j=0). - // Reuses the u_* MAC/INTT/ADD machine with u_row tied to 0. + // 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 @@ -2211,8 +2210,8 @@ module mlkem_top #( pm_valid <= 1'b0; end - // Arm D3 (ST_DEC_W) when D2 NTT finishes: same u_* MAC/INTT machine, - // single row (u_row 0..0). MAC s_hat[j] o u_hat[j], INTT, then SUB. + // 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 @@ -2224,7 +2223,7 @@ module mlkem_top #( pm_valid <= 1'b0; end - // Arm D4 (ST_DEC_MENC) when D3 w done: byteEncode_1(Compress_1(w)). + // 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; @@ -2232,12 +2231,12 @@ module mlkem_top #( end // ---- ST_DEC_MENC (D4): m' = byteEncode_1(Compress_1(w)) ---- - // Compress_1(w)=1 iff 832 < w <= 2496 (Q=3329). Pack 256 bits - // LSB-first into m_r (bit men_idx). Read w from bank_t[UPSUM]. - // ph0: present w[men_idx] addr; ph1: bt_rd_data valid -> set bit. + // 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; // addr presented; wait read + 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;