Files
mlkem-sync/sync_rtl/sha3_chain/sha3_chain_top_shared.v
FallenSigh 03b4707879 feat(top): add shared keccak variants, arbiter, and mlkem_top integration
- sha3_chain_top_shared.v: external keccak_core interface (6 ports)
- sample_cbd_sync_shared.v: shared keccak variant (6 ports)
- sample_ntt_sync_shared.v: shared keccak variant (6 ports)
- keccak_arbiter.v: fixed-priority arbiter for 3 keccak consumers
- mlkem_top.v: 1403-line monolithic FSM with KeyGen/Encaps/Decaps

Architecture:
  keccak_arbiter → keccak_core → keccak_round (shared)
  sha3_chain_top_shared (consumer 0)
  sample_cbd_sync_shared (consumer 1)
  sample_ntt_sync_shared (consumer 2)
  sha3_top (separate, own keccak_core)
  rng_sync, ntt_core, poly_arith, poly_mul, comp_decomp, mod_add
  sd_bram for polynomial storage

All original RTL files preserved unchanged.
2026-06-26 03:35:37 +08:00

116 lines
4.6 KiB
Verilog

// sha3_chain_top_shared.v - SHA3-512 chain: G(d||k=2) → rho, sigma
//
// Refactored version that accepts an external keccak_core interface instead
// of instantiating sha3_top internally. Designed for shared-keccak top-level
// integration where a single keccak_core is time-multiplexed via an arbiter.
//
// The internal logic replicates sha3_top's G-mode absorb-state construction
// and keccak sequencing, but exposes keccak_core signals through the port
// list so the arbiter can route them.
//
// 3-state FSM: IDLE → BUSY → DONE
//
// Interface:
// clk, rst_n - clock, active-low reset
// d_in[255:0] - 256-bit d input (external, NOT from RNG)
// start_i - start computation
// done_o - computation complete (pulsed for duration of DONE)
// rho_out[255:0] - G output first 256 bits
// sigma_out[255:0] - G output next 256 bits
// kc_state_o[1599:0]- from keccak_core output (post-permutation state)
// kc_valid_o - from keccak_core (permutation complete)
// kc_ready_i - to keccak_core (always accept output = 1'b1)
// kc_state_i[1599:0]- to keccak_core input (pre-permutation state)
// kc_valid_i - to keccak_core (start permutation pulse)
// kc_ready_o - from keccak_core (core is idle / can accept)
module sha3_chain_top_shared (
input clk,
input rst_n,
input [255:0] d_in,
input start_i,
output done_o,
output [255:0] rho_out,
output [255:0] sigma_out,
// keccak_core interface (connect to shared arbiter)
input [1599:0] kc_state_o,
input kc_valid_o,
output kc_ready_i,
output [1599:0] kc_state_i,
output kc_valid_i,
input kc_ready_o
);
localparam ST_IDLE = 2'd0;
localparam ST_BUSY = 2'd1;
localparam ST_DONE = 2'd2;
reg [1:0] state_r, state_next;
// ================================================================
// Absorb state: message || suffix || pad10*1 into rate bits
//
// Replicates sha3_top G-mode absorb_state construction:
// data_i = {248'b0, k=8'd2, d_in}
// G: padded_block = {1'b1, {308{1'b0}}, 1'b1, 2'b10, data_i[263:0]}
// absorb_state = {1024'b0, padded_block_576}
// ================================================================
wire [511:0] sha3_data_i;
wire [575:0] g_pad;
wire [1599:0] absorb_state;
assign sha3_data_i = {248'b0, 8'd2, d_in};
assign g_pad = {1'b1, {308{1'b0}}, 1'b1, 2'b10, sha3_data_i[263:0]};
assign absorb_state = {{(1600-576){1'b0}}, g_pad};
// ================================================================
// keccak_core interface connections
// ================================================================
assign kc_ready_i = 1'b1; // always accept output
assign kc_state_i = absorb_state; // feed absorb state combinationally
assign kc_valid_i = (state_next == ST_BUSY); // start keccak on IDLE → BUSY
// done_o: asserted for duration of DONE state
assign done_o = (state_r == ST_DONE);
// ================================================================
// Output registers
// ================================================================
reg [255:0] rho_out_r, sigma_out_r;
assign rho_out = rho_out_r;
assign sigma_out = sigma_out_r;
// ================================================================
// FSM combinational next-state
// ================================================================
always @(*) begin
state_next = state_r;
case (state_r)
ST_IDLE: if (start_i && kc_ready_o) state_next = ST_BUSY;
ST_BUSY: if (kc_valid_o) state_next = ST_DONE;
ST_DONE: if (!start_i) state_next = ST_IDLE;
default: state_next = ST_IDLE;
endcase
end
// ================================================================
// Sequential logic
// ================================================================
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_r <= ST_IDLE;
rho_out_r <= 256'd0;
sigma_out_r <= 256'd0;
end else begin
state_r <= state_next;
// Capture squeezed output when BUSY → DONE
if (state_r == ST_BUSY && kc_valid_o) begin
rho_out_r <= kc_state_o[255:0];
sigma_out_r <= kc_state_o[511:256];
end
end
end
endmodule