// keccak_round.v - Single Keccak-f round (theta/rho/pi/chi/iota) // // Pure combinational: no clock, no valid/ready. // Input: 1600-bit state, 5-bit round index (0-23). // Output: transformed 1600-bit state. // // State layout: s[64*(5*y + x) + z] = A[x][y][z] // Lane(x,y) = s[64*(5*y + x) +: 64] module keccak_round ( input [1599:0] state_i, input [4:0] round_i, output [1599:0] state_o ); // ================================================================ // Round constants (24 entries, FIPS 202) // ================================================================ wire [63:0] RC [0:23]; assign RC[ 0] = 64'h0000000000000001; assign RC[ 1] = 64'h0000000000008082; assign RC[ 2] = 64'h800000000000808A; assign RC[ 3] = 64'h8000000080008000; assign RC[ 4] = 64'h000000000000808B; assign RC[ 5] = 64'h0000000080000001; assign RC[ 6] = 64'h8000000080008081; assign RC[ 7] = 64'h8000000000008009; assign RC[ 8] = 64'h000000000000008A; assign RC[ 9] = 64'h0000000000000088; assign RC[10] = 64'h0000000080008009; assign RC[11] = 64'h000000008000000A; assign RC[12] = 64'h000000008000808B; assign RC[13] = 64'h800000000000008B; assign RC[14] = 64'h8000000000008089; assign RC[15] = 64'h8000000000008003; assign RC[16] = 64'h8000000000008002; assign RC[17] = 64'h8000000000000080; assign RC[18] = 64'h000000000000800A; assign RC[19] = 64'h800000008000000A; assign RC[20] = 64'h8000000080008081; assign RC[21] = 64'h8000000000008080; assign RC[22] = 64'h0000000080000001; assign RC[23] = 64'h8000000080008008; // ================================================================ // Rho rotation offsets (FIPS 202, Table 2) // Inlined as generate-if chains for tool compatibility // ================================================================ // ================================================================ // Unpack flat 1600-bit input into 25 lanes (each 64-bit) // Lane index: 5*y + x // ================================================================ wire [63:0] A [0:4][0:4]; genvar gx, gy; generate for (gx = 0; gx < 5; gx = gx + 1) begin : up_x for (gy = 0; gy < 5; gy = gy + 1) begin : up_y assign A[gx][gy] = state_i[((5 * gy + gx) * 64) +: 64]; end end endgenerate // ================================================================ // Theta step // C[x] = XOR over y of A[x][y] // D[x] = C[x-1] ^ ROTL(C[x+1], 1) // A_theta[x][y] = A[x][y] ^ D[x] // ================================================================ wire [63:0] C [0:4]; wire [63:0] D [0:4]; wire [63:0] A_t [0:4][0:4]; generate for (gx = 0; gx < 5; gx = gx + 1) begin : th_x // C[x] = XOR of the 5 lanes in column x assign C[gx] = A[gx][0] ^ A[gx][1] ^ A[gx][2] ^ A[gx][3] ^ A[gx][4]; // D[x] = C[(x-1) mod 5] ^ ROTL(C[(x+1) mod 5], 1) localparam [2:0] xp1 = (gx == 4) ? 3'd0 : (gx + 3'd1); localparam [2:0] xm1 = (gx == 0) ? 3'd4 : (gx - 3'd1); assign D[gx] = C[xm1] ^ {C[xp1][62:0], C[xp1][63]}; for (gy = 0; gy < 5; gy = gy + 1) begin : th_y assign A_t[gx][gy] = A[gx][gy] ^ D[gx]; end end endgenerate // ================================================================ // Rho step (rotation of each lane by precomputed offset) // ================================================================ wire [63:0] A_r [0:4][0:4]; generate for (gx = 0; gx < 5; gx = gx + 1) begin : rh_x for (gy = 0; gy < 5; gy = gy + 1) begin : rh_y if (gx == 0 && gy == 0) begin : rho_00 assign A_r[gx][gy] = A_t[gx][gy]; end else if (gy == 0 && gx == 1) begin : rho_10 assign A_r[gx][gy] = {A_t[gx][gy][62:0], A_t[gx][gy][63]}; end else if (gy == 0 && gx == 2) begin : rho_20 assign A_r[gx][gy] = {A_t[gx][gy][1:0], A_t[gx][gy][63:2]}; end else if (gy == 0 && gx == 3) begin : rho_30 assign A_r[gx][gy] = {A_t[gx][gy][35:0], A_t[gx][gy][63:36]}; end else if (gy == 0 && gx == 4) begin : rho_40 assign A_r[gx][gy] = {A_t[gx][gy][36:0], A_t[gx][gy][63:37]}; end else if (gy == 1 && gx == 0) begin : rho_01 assign A_r[gx][gy] = {A_t[gx][gy][27:0], A_t[gx][gy][63:28]}; end else if (gy == 1 && gx == 1) begin : rho_11 assign A_r[gx][gy] = {A_t[gx][gy][19:0], A_t[gx][gy][63:20]}; end else if (gy == 1 && gx == 2) begin : rho_21 assign A_r[gx][gy] = {A_t[gx][gy][57:0], A_t[gx][gy][63:58]}; end else if (gy == 1 && gx == 3) begin : rho_31 assign A_r[gx][gy] = {A_t[gx][gy][8:0], A_t[gx][gy][63:9]}; end else if (gy == 1 && gx == 4) begin : rho_41 assign A_r[gx][gy] = {A_t[gx][gy][43:0], A_t[gx][gy][63:44]}; end else if (gy == 2 && gx == 0) begin : rho_02 assign A_r[gx][gy] = {A_t[gx][gy][60:0], A_t[gx][gy][63:61]}; end else if (gy == 2 && gx == 1) begin : rho_12 assign A_r[gx][gy] = {A_t[gx][gy][53:0], A_t[gx][gy][63:54]}; end else if (gy == 2 && gx == 2) begin : rho_22 assign A_r[gx][gy] = {A_t[gx][gy][20:0], A_t[gx][gy][63:21]}; end else if (gy == 2 && gx == 3) begin : rho_32 assign A_r[gx][gy] = {A_t[gx][gy][38:0], A_t[gx][gy][63:39]}; end else if (gy == 2 && gx == 4) begin : rho_42 assign A_r[gx][gy] = {A_t[gx][gy][24:0], A_t[gx][gy][63:25]}; end else if (gy == 3 && gx == 0) begin : rho_03 assign A_r[gx][gy] = {A_t[gx][gy][22:0], A_t[gx][gy][63:23]}; end else if (gy == 3 && gx == 1) begin : rho_13 assign A_r[gx][gy] = {A_t[gx][gy][18:0], A_t[gx][gy][63:19]}; end else if (gy == 3 && gx == 2) begin : rho_23 assign A_r[gx][gy] = {A_t[gx][gy][48:0], A_t[gx][gy][63:49]}; end else if (gy == 3 && gx == 3) begin : rho_33 assign A_r[gx][gy] = {A_t[gx][gy][42:0], A_t[gx][gy][63:43]}; end else if (gy == 3 && gx == 4) begin : rho_43 assign A_r[gx][gy] = {A_t[gx][gy][55:0], A_t[gx][gy][63:56]}; end else if (gy == 4 && gx == 0) begin : rho_04 assign A_r[gx][gy] = {A_t[gx][gy][45:0], A_t[gx][gy][63:46]}; end else if (gy == 4 && gx == 1) begin : rho_14 assign A_r[gx][gy] = {A_t[gx][gy][61:0], A_t[gx][gy][63:62]}; end else if (gy == 4 && gx == 2) begin : rho_24 assign A_r[gx][gy] = {A_t[gx][gy][2:0], A_t[gx][gy][63:3]}; end else if (gy == 4 && gx == 3) begin : rho_34 assign A_r[gx][gy] = {A_t[gx][gy][7:0], A_t[gx][gy][63:8]}; end else if (gy == 4 && gx == 4) begin : rho_44 assign A_r[gx][gy] = {A_t[gx][gy][49:0], A_t[gx][gy][63:50]}; end end end endgenerate // ================================================================ // Pi step (permute lanes) // A_pi[x][y] = A_rho[(x + 3*y) % 5][x] // ================================================================ wire [63:0] A_p [0:4][0:4]; generate for (gx = 0; gx < 5; gx = gx + 1) begin : pi_x for (gy = 0; gy < 5; gy = gy + 1) begin : pi_y localparam [2:0] src_x = (gx + 3 * gy) % 5; assign A_p[gx][gy] = A_r[src_x][gx]; end end endgenerate // ================================================================ // Chi step // A_chi[x][y] = A_pi[x][y] ^ (~A_pi[x+1][y] & A_pi[x+2][y]) // ================================================================ wire [63:0] A_c [0:4][0:4]; generate for (gx = 0; gx < 5; gx = gx + 1) begin : ch_x localparam [2:0] xp1 = (gx == 4) ? 3'd0 : (gx + 3'd1); localparam [2:0] xp2 = (gx == 3) ? 3'd0 : (gx == 4) ? 3'd1 : (gx + 3'd2); for (gy = 0; gy < 5; gy = gy + 1) begin : ch_y assign A_c[gx][gy] = A_p[gx][gy] ^ ((~A_p[xp1][gy]) & A_p[xp2][gy]); end end endgenerate // ================================================================ // Iota step // A_iota[0][0] = A_chi[0][0] ^ RC[round_i] // Other lanes unchanged // ================================================================ wire [63:0] A_io [0:4][0:4]; assign A_io[0][0] = A_c[0][0] ^ RC[round_i]; assign A_io[0][1] = A_c[0][1]; assign A_io[0][2] = A_c[0][2]; assign A_io[0][3] = A_c[0][3]; assign A_io[0][4] = A_c[0][4]; assign A_io[1][0] = A_c[1][0]; assign A_io[1][1] = A_c[1][1]; assign A_io[1][2] = A_c[1][2]; assign A_io[1][3] = A_c[1][3]; assign A_io[1][4] = A_c[1][4]; assign A_io[2][0] = A_c[2][0]; assign A_io[2][1] = A_c[2][1]; assign A_io[2][2] = A_c[2][2]; assign A_io[2][3] = A_c[2][3]; assign A_io[2][4] = A_c[2][4]; assign A_io[3][0] = A_c[3][0]; assign A_io[3][1] = A_c[3][1]; assign A_io[3][2] = A_c[3][2]; assign A_io[3][3] = A_c[3][3]; assign A_io[3][4] = A_c[3][4]; assign A_io[4][0] = A_c[4][0]; assign A_io[4][1] = A_c[4][1]; assign A_io[4][2] = A_c[4][2]; assign A_io[4][3] = A_c[4][3]; assign A_io[4][4] = A_c[4][4]; // ================================================================ // Pack 25 lanes back into 1600-bit flat output // ================================================================ assign state_o = {A_io[4][4], A_io[3][4], A_io[2][4], A_io[1][4], A_io[0][4], A_io[4][3], A_io[3][3], A_io[2][3], A_io[1][3], A_io[0][3], A_io[4][2], A_io[3][2], A_io[2][2], A_io[1][2], A_io[0][2], A_io[4][1], A_io[3][1], A_io[2][1], A_io[1][1], A_io[0][1], A_io[4][0], A_io[3][0], A_io[2][0], A_io[1][0], A_io[0][0]}; endmodule