feat(sha3): implement synchronous Keccak-f[1600] core with G/H/J modes
Phase 1.1 of ML-KEM sync rewrite. - keccak_round.v: combinational theta/rho/pi/chi/iota - keccak_core.v: 24-round pipeline, valid/ready - sha3_top.v: sponge FSM, modes G(SHA3-512)/H(SHA3-256)/J(SHAKE-256) - Verilator C++ TB + Python vector gen against reference - Verified: 25/25 vectors bit-exact vs Python G()/H()/J()
This commit is contained in:
99
sync_rtl/sha3/keccak_core.v
Normal file
99
sync_rtl/sha3/keccak_core.v
Normal file
@@ -0,0 +1,99 @@
|
||||
// keccak_core.v - Synchronous Keccak-f[1600] core with valid/ready
|
||||
//
|
||||
// Runs 24 rounds of keccak_round on the input state.
|
||||
// valid_i high with ready_o high → load state_i, start 24-round sequence.
|
||||
// Each round takes 1 cycle. After round 23, valid_o asserted with state_o.
|
||||
//
|
||||
// Parameter:
|
||||
// ROUNDS = 24 (default)
|
||||
//
|
||||
// Interface:
|
||||
// clk, rst_n - clock, active-low reset
|
||||
// state_i - 1600-bit input state
|
||||
// valid_i - start permutation
|
||||
// ready_o - core can accept new input
|
||||
// state_o - 1600-bit output state (after permutation)
|
||||
// valid_o - output is valid
|
||||
// ready_i - consumer accepts output
|
||||
|
||||
module keccak_core #(parameter ROUNDS = 24) (
|
||||
input clk,
|
||||
input rst_n,
|
||||
input [1599:0] state_i,
|
||||
input valid_i,
|
||||
output ready_o,
|
||||
output [1599:0] state_o,
|
||||
output valid_o,
|
||||
input ready_i
|
||||
);
|
||||
|
||||
// ================================================================
|
||||
// Internal registers
|
||||
// ================================================================
|
||||
reg busy_r; // 1 while running permutation
|
||||
reg [4:0] cnt_r; // round counter (0 to ROUNDS-1)
|
||||
reg [1599:0] state_r; // current state
|
||||
|
||||
// ================================================================
|
||||
// Next-state logic
|
||||
// ================================================================
|
||||
wire cnt_is_last; // cnt_r == ROUNDS-1 ?
|
||||
wire [1599:0] state_next; // combinational round output
|
||||
|
||||
assign cnt_is_last = (cnt_r == (ROUNDS - 1));
|
||||
|
||||
// keccak_round: apply one round to current state
|
||||
keccak_round u_round (
|
||||
.state_i(state_r),
|
||||
.round_i(cnt_r),
|
||||
.state_o(state_next)
|
||||
);
|
||||
|
||||
// ================================================================
|
||||
// Valid/ready handshake
|
||||
// ================================================================
|
||||
// ready_o: accept new input when not busy (or just finishing)
|
||||
assign ready_o = !busy_r;
|
||||
|
||||
// valid_o: output valid when we just finished the last round
|
||||
// (the final state is already in state_r at the output cycle)
|
||||
assign valid_o = busy_r && cnt_is_last;
|
||||
|
||||
// state_o: output the final state
|
||||
assign state_o = state_next; // final state from the last round
|
||||
|
||||
// ================================================================
|
||||
// Sequential logic
|
||||
// ================================================================
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
busy_r <= 1'b0;
|
||||
cnt_r <= 5'd0;
|
||||
state_r <= 1600'd0;
|
||||
end else begin
|
||||
if (!busy_r) begin
|
||||
// IDLE: wait for valid_i
|
||||
if (valid_i) begin
|
||||
state_r <= state_i;
|
||||
cnt_r <= 5'd0;
|
||||
busy_r <= 1'b1;
|
||||
end
|
||||
end else begin
|
||||
// BUSY: running permutations
|
||||
if (cnt_is_last) begin
|
||||
// Final round: check if output can be accepted
|
||||
if (ready_i) begin
|
||||
busy_r <= 1'b0;
|
||||
cnt_r <= 5'd0;
|
||||
end
|
||||
// else: hold until ready_i
|
||||
end else begin
|
||||
// Intermediate round: advance state
|
||||
state_r <= state_next;
|
||||
cnt_r <= cnt_r + 5'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user