From 851630f73c2875ffecb014fea870fec5f554a842 Mon Sep 17 00:00:00 2001 From: FallenSigh Date: Sun, 28 Jun 2026 15:22:28 +0800 Subject: [PATCH] refactor(kg): merge G/H into single shared sha3_top (4->3 keccak_core) ST_G (single-block G) and ST_H (multi-block H(ek)) are disjoint FSM phases, so one sha3_top serves both: mb_en and ready_i are phase-muxed, h_hash/h_vo alias the shared core's outputs. Removes the dedicated u_sha3_h instance and its keccak_core. 11/11 KAT PASS (K=2 c0-4, K=3/4 c0-2), byte-exact, 0 file-not-found. --- sync_rtl/top/mlkem_top.v | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/sync_rtl/top/mlkem_top.v b/sync_rtl/top/mlkem_top.v index 2e2db77..e4b24cb 100644 --- a/sync_rtl/top/mlkem_top.v +++ b/sync_rtl/top/mlkem_top.v @@ -179,20 +179,29 @@ module mlkem_top #( reg sha3_ack; // consumer ready for hash wire [511:0] g_data = {248'b0, 5'b0, k_r, d_i}; // data_i[263:256]=k, [255:0]=d + // ---- single shared sha3_top serving BOTH G and H ---- + // G (ST_G) uses single-block mode (mb_en=0); H(ek) (ST_H) uses the + // multi-block absorb path (mb_en=1). These phases are disjoint in the + // top FSM, so one sha3_top (one keccak_core) is sufficient. mb_en and + // ready_i are muxed by phase; data_i/mode only matter while mb_en=0. + wire sha3_mb_en = (st == ST_H); sha3_top u_sha3 ( .clk(clk), .rst_n(rst_n), - .mode(2'b00), // G = SHA3-512 + .mode(2'b00), // G = SHA3-512 (only used when mb_en=0) .data_i(g_data), .valid_i(sha3_valid), .ready_o(sha3_ready), .hash_o(sha3_hash), .valid_o(sha3_vo), - .ready_i(sha3_ack), - .mb_en(1'b0), .mb_block_i(1088'b0), .mb_valid_i(1'b0), - .mb_last_i(1'b0), .mb_ready_o() + .ready_i(sha3_mb_en ? h_ack : sha3_ack), + .mb_en(sha3_mb_en), + .mb_block_i(h_block_r), + .mb_valid_i(h_mbvalid), + .mb_last_i(h_mblast), + .mb_ready_o(h_mbready) ); - // ---- second sha3_top dedicated to multi-block H(ek) (SHA3-256, 800B->6 blk) ---- + // ---- 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 reg h_mbvalid; reg h_mblast; @@ -213,21 +222,11 @@ module mlkem_top #( 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) - sha3_top u_sha3_h ( - .clk(clk), .rst_n(rst_n), - .mode(2'b01), // unused in mb mode - .data_i(512'b0), - .valid_i(1'b0), - .ready_o(), - .hash_o(h_hash), - .valid_o(h_vo), - .ready_i(h_ack), - .mb_en(1'b1), - .mb_block_i(h_block_r), - .mb_valid_i(h_mbvalid), - .mb_last_i(h_mblast), - .mb_ready_o(h_mbready) - ); + // 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. + 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.