| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| // |
| // SHA-256 Padding logic |
| // |
| |
| `include "prim_assert.sv" |
| |
| module sha2_pad import hmac_pkg::*; ( |
| input clk_i, |
| input rst_ni, |
| |
| input wipe_secret, |
| input sha_word_t wipe_v, |
| |
| // To actual FIFO |
| input fifo_rvalid, |
| input sha_fifo_t fifo_rdata, |
| output logic fifo_rready, |
| |
| // from SHA2 compress engine |
| output logic shaf_rvalid, |
| output sha_word_t shaf_rdata, |
| input shaf_rready, |
| |
| input sha_en, |
| input hash_start, |
| input hash_process, |
| input hash_done, |
| |
| input [63:0] message_length, // # of bytes in bits (8 bits granularity) |
| output logic msg_feed_complete // Indicates, all message is feeded |
| ); |
| |
| //logic [8:0] length_added; |
| |
| logic [63:0] tx_count; // fin received data count. |
| |
| logic inc_txcount; |
| logic fifo_partial; |
| logic txcnt_eq_1a0; |
| logic hash_process_flag; // Set by hash_process, clear by hash_done |
| |
| assign fifo_partial = ~&fifo_rdata.mask; |
| |
| // tx_count[8:0] == 'h1c0 --> should send LenHi |
| assign txcnt_eq_1a0 = (tx_count[8:0] == 9'h1a0); |
| |
| always_ff @(posedge clk_i or negedge rst_ni) begin |
| if (!rst_ni) begin |
| hash_process_flag <= 1'b0; |
| end else if (hash_process) begin |
| hash_process_flag <= 1'b1; |
| end else if (hash_done || hash_start) begin |
| hash_process_flag <= 1'b0; |
| end |
| end |
| |
| // Data path: fout_wdata |
| typedef enum logic [2:0] { |
| FifoIn, // fin_wdata, fin_wstrb |
| Pad80, // {8'h80, 8'h00} , strb (calc based on len[4:3]) |
| Pad00, // 32'h0, full strb |
| LenHi, // len[63:32], full strb |
| LenLo // len[31:0], full strb |
| } sel_data_e; |
| sel_data_e sel_data; |
| |
| always_comb begin |
| unique case (sel_data) |
| FifoIn: begin |
| shaf_rdata = fifo_rdata.data; |
| end |
| |
| Pad80: begin |
| // {a[7:0], b[7:0], c[7:0], d[7:0]} |
| // msglen[4:3] == 00 |-> {'h80, 'h00, 'h00, 'h00} |
| // msglen[4:3] == 01 |-> {msg, 'h80, 'h00, 'h00} |
| // msglen[4:3] == 10 |-> {msg[15:0], 'h80, 'h00} |
| // msglen[4:3] == 11 |-> {msg[23:0], 'h80} |
| unique case (message_length[4:3]) |
| 2'b 00: shaf_rdata = 32'h 8000_0000; |
| 2'b 01: shaf_rdata = {fifo_rdata.data[31:24], 24'h 8000_00}; |
| 2'b 10: shaf_rdata = {fifo_rdata.data[31:16], 16'h 8000}; |
| 2'b 11: shaf_rdata = {fifo_rdata.data[31: 8], 8'h 80}; |
| default: shaf_rdata = 32'h0; |
| endcase |
| end |
| |
| Pad00: begin |
| shaf_rdata = '0; |
| end |
| |
| LenHi: begin |
| shaf_rdata = message_length[63:32]; |
| end |
| |
| LenLo: begin |
| shaf_rdata = message_length[31:0]; |
| end |
| |
| default: begin |
| shaf_rdata = '0; |
| end |
| endcase |
| end |
| |
| // Padded length |
| // $ceil(message_length + 8 + 64, 512) -> message_length [8:0] + 440 and ignore carry |
| //assign length_added = (message_length[8:0] + 9'h1b8) ; |
| |
| // fifo control |
| // add 8'h 80 , N 8'h00, 64'h message_length |
| |
| // Steps |
| // 1. `hash_start` from CPU (or DMA?) |
| // 2. calculate `padded_length` from `message_length` |
| // 3. Check if tx_count == message_length, then go to 5 |
| // 4. Receiving FIFO input (hand over to fifo output) |
| // 5. Padding bit 1 (8'h80) followed by 8'h00 if needed |
| // 6. Padding with length (high -> low) |
| |
| // State Machine |
| typedef enum logic [2:0] { |
| StIdle, // fin_full to prevent unwanted FIFO write |
| StFifoReceive, // Check tx_count == message_length |
| StPad80, // 8'h 80 + 8'h 00 X N |
| StPad00, |
| StLenHi, |
| StLenLo |
| } pad_st_e; |
| |
| pad_st_e st_q, st_d; |
| |
| always_ff @(posedge clk_i or negedge rst_ni) begin |
| if (!rst_ni) begin |
| st_q <= StIdle; |
| end else begin |
| st_q <= st_d; |
| end |
| end |
| |
| // Next state |
| always_comb begin |
| shaf_rvalid = 1'b0; |
| inc_txcount = 1'b0; |
| sel_data = FifoIn; |
| fifo_rready = 1'b0; |
| |
| st_d = StIdle; |
| |
| unique case (st_q) |
| StIdle: begin |
| sel_data = FifoIn; |
| shaf_rvalid = 1'b0; |
| |
| if (sha_en && hash_start) begin |
| inc_txcount = 1'b0; |
| |
| st_d = StFifoReceive; |
| end else begin |
| st_d = StIdle; |
| end |
| end |
| |
| StFifoReceive: begin |
| sel_data = FifoIn; |
| |
| if (fifo_partial && fifo_rvalid) begin |
| // End of the message, assume hash_process_flag is set |
| shaf_rvalid = 1'b0; // Update entry at StPad80 |
| inc_txcount = 1'b0; |
| fifo_rready = 1'b0; |
| |
| st_d = StPad80; |
| end else if (!hash_process_flag) begin |
| fifo_rready = shaf_rready; |
| shaf_rvalid = fifo_rvalid; |
| inc_txcount = shaf_rready; |
| |
| st_d = StFifoReceive; |
| end else if (tx_count == message_length) begin |
| // already received all msg and was waiting process flag |
| shaf_rvalid = 1'b0; |
| inc_txcount = 1'b0; |
| fifo_rready = 1'b0; |
| |
| st_d = StPad80; |
| end else begin |
| shaf_rvalid = fifo_rvalid; |
| fifo_rready = shaf_rready; // 0 always |
| inc_txcount = shaf_rready; // 0 always |
| |
| st_d = StFifoReceive; |
| end |
| end |
| |
| StPad80: begin |
| sel_data = Pad80; |
| |
| shaf_rvalid = 1'b1; |
| fifo_rready = shaf_rready && |message_length[4:3]; // Only when partial |
| |
| // exactly 96 bits left, do not need to pad00's |
| if (shaf_rready && txcnt_eq_1a0) begin |
| st_d = StLenHi; |
| inc_txcount = 1'b1; |
| // it does not matter if value is < or > than 416 bits. If it's the former, 00 pad until |
| // length field. If >, then the next chunk will contain the length field with appropriate |
| // 0 padding. |
| end else if (shaf_rready && !txcnt_eq_1a0) begin |
| st_d = StPad00; |
| inc_txcount = 1'b1; |
| end else begin |
| st_d = StPad80; |
| inc_txcount = 1'b0; |
| end |
| |
| // # Below part is temporal code to speed up the SHA by 16 clocks per chunk |
| // # (80 clk --> 64 clk) |
| // # leaving this as a reference but needs to verify it. |
| //if (shaf_rready && !txcnt_eq_1a0) begin |
| // st_d = StPad00; |
| // |
| // inc_txcount = 1'b1; |
| // shaf_rvalid = (msg_word_aligned) ? 1'b1 : fifo_rvalid; |
| // fifo_rready = (msg_word_aligned) ? 1'b0 : 1'b1; |
| //end else if (!shaf_rready && !txcnt_eq_1a0) begin |
| // st_d = StPad80; |
| // |
| // inc_txcount = 1'b0; |
| // shaf_rvalid = (msg_word_aligned) ? 1'b1 : fifo_rvalid; |
| // |
| //end else if (shaf_rready && txcnt_eq_1a0) begin |
| // st_d = StLenHi; |
| // inc_txcount = 1'b1; |
| //end else begin |
| // // !shaf_rready && txcnt_eq_1a0 , just wait until fifo_rready asserted |
| // st_d = StPad80; |
| // inc_txcount = 1'b0; |
| //end |
| end |
| |
| StPad00: begin |
| sel_data = Pad00; |
| shaf_rvalid = 1'b1; |
| |
| if (shaf_rready) begin |
| inc_txcount = 1'b1; |
| |
| if (txcnt_eq_1a0) begin |
| st_d = StLenHi; |
| end else begin |
| st_d = StPad00; |
| end |
| end else begin |
| st_d = StPad00; |
| end |
| end |
| |
| StLenHi: begin |
| sel_data = LenHi; |
| shaf_rvalid = 1'b1; |
| |
| if (shaf_rready) begin |
| st_d = StLenLo; |
| |
| inc_txcount = 1'b1; |
| end else begin |
| st_d = StLenHi; |
| |
| inc_txcount = 1'b0; |
| end |
| end |
| |
| StLenLo: begin |
| sel_data = LenLo; |
| shaf_rvalid = 1'b1; |
| |
| if (shaf_rready) begin |
| st_d = StIdle; |
| |
| inc_txcount = 1'b1; |
| end else begin |
| st_d = StLenLo; |
| |
| inc_txcount = 1'b0; |
| end |
| end |
| |
| default: begin |
| st_d = StIdle; |
| end |
| endcase |
| end |
| |
| // tx_count |
| always_ff @(posedge clk_i or negedge rst_ni) begin |
| if (!rst_ni) begin |
| tx_count <= '0; |
| end else if (hash_start) begin |
| tx_count <= '0; |
| end else if (inc_txcount) begin |
| tx_count[63:5] <= tx_count[63:5] + 1'b1; |
| end |
| end |
| |
| // State machine is in Idle only when it meets tx_count == message length |
| assign msg_feed_complete = hash_process_flag && (st_q == StIdle); |
| |
| endmodule |