// 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