feat(enc): Encaps E0 - op_i/msg_i/ek-load scaffold + H(ek)+G(m||H(ek))

Extend mlkem_top with a runtime op_i select (0=KeyGen, 1=Encaps) and the
first Encaps stages, reusing the shared keccak_core and the ST_H multi-block
SHA3-256 machinery:
  ST_ENC_H: H(ek) over preloaded ek_bram (same FSM as KeyGen ST_H)
  ST_ENC_G: (K,r) = G(m||H(ek)) via new 64-byte single-block SHA3-512

- sha3_top_shared: add mode=2'b11 = SHA3-512 over a full 512-bit message
  (g512_pad). Standalone tb_sha3_g512 confirms it byte-exact.
- mlkem_top: new ports op_i, msg_i, ek_in_{we,addr,byte} (ek preload), ss_o,
  dbg_ct_*, dbg_r_o/dbg_hek_o. st widened 4->5 bits; ST_ENC_* states added.
  Renamed message port to msg_i to avoid collision with ST_M counter m_i.
- TB tb_mlkem_enc_katK + gen_encaps_vectors.py (per-byte ek/m/ct/ss vectors).

Verified ss==KAT.ss for K=2/3/4, cases 0-2 (all PASS). KeyGen unaffected
(K=2 c0 still ek==pk, dk==sk byte-exact).
This commit is contained in:
2026-06-29 01:00:47 +08:00
parent c4669480d1
commit 0a8b3dae69
43 changed files with 21956 additions and 30 deletions

View File

@@ -19,12 +19,16 @@ module tb_mlkem_kg_katK_xsim;
// KMAX defaults to 4 (worst-case sizing); KP selects the runtime k value.
mlkem_top dut (
.clk(clk), .rst_n(rst_n), .k_i(k_i), .d_i(d_i), .z_i(z_i), .start_i(start_i),
.clk(clk), .rst_n(rst_n), .k_i(k_i), .op_i(1'b0),
.d_i(d_i), .z_i(z_i), .msg_i(256'd0), .start_i(start_i),
.busy_o(busy_o), .done_o(done_o),
.ek_in_we(1'b0), .ek_in_addr(11'd0), .ek_in_byte(8'd0),
.ss_o(), .dbg_ct_idx_i(11'd0), .dbg_ct_o(),
.dbg_slot_i(dbg_slot_i), .dbg_idx_i(dbg_idx_i), .dbg_coeff_o(dbg_coeff_o),
.dbg_byte_sel_i(dbg_byte_sel_i), .dbg_byte_idx_i(dbg_byte_idx_i), .dbg_byte_o(dbg_byte_o),
.dbg_dk_idx_i(dbg_dk_idx_i), .dbg_dk_o(dbg_dk_o),
.dbg_rho_o(dbg_rho_o), .dbg_sigma_o(dbg_sigma_o)
.dbg_rho_o(dbg_rho_o), .dbg_sigma_o(dbg_sigma_o),
.dbg_r_o(), .dbg_hek_o()
);
always #5 clk = ~clk;