- 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.
116 lines
4.6 KiB
Verilog
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
|