hw/ip/hmac/rtl/sha2_pad.sv Cov: 100%

   1: // Copyright lowRISC contributors.
   2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
   3: // SPDX-License-Identifier: Apache-2.0
   4: //
   5: // SHA-256 Padding logic
   6: //
   7: 
   8: module sha2_pad import hmac_pkg::*; (
   9:   input clk_i,
  10:   input rst_ni,
  11: 
  12:   input            wipe_secret,
  13:   input sha_word_t wipe_v,
  14: 
  15:   // To actual FIFO
  16:   input                 fifo_rvalid,
  17:   input  sha_fifo_t     fifo_rdata,
  18:   output logic          fifo_rready,
  19: 
  20:   // from SHA2 compress engine
  21:   output logic          shaf_rvalid,
  22:   output sha_word_t     shaf_rdata,
  23:   input                 shaf_rready,
  24: 
  25:   input sha_en,
  26:   input hash_start,
  27:   input hash_process,
  28:   input hash_done,
  29: 
  30:   input        [63:0] message_length, // # of bytes in bits (8 bits granularity)
  31:   output logic        msg_feed_complete // Indicates, all message is feeded
  32: );
  33: 
  34:   //logic [8:0] length_added;
  35: 
  36:   logic [63:0] tx_count;    // fin received data count.
  37: 
  38:   logic inc_txcount;
  39:   logic fifo_partial;
  40:   logic txcnt_eq_1a0;
  41:   logic hash_process_flag; // Set by hash_process, clear by hash_done
  42: 
  43:   assign fifo_partial = ~&fifo_rdata.mask;
  44: 
  45:   // tx_count[8:0] == 'h1c0 --> should send LenHi
  46:   assign txcnt_eq_1a0 = (tx_count[8:0] == 9'h1a0);
  47: 
  48:   always_ff @(posedge clk_i or negedge rst_ni) begin
  49:     if (!rst_ni) begin
  50:       hash_process_flag <= 1'b0;
  51:     end else if (hash_process) begin
  52:       hash_process_flag <= 1'b1;
  53:     end else if (hash_done || hash_start) begin
  54:       hash_process_flag <= 1'b0;
  55:     end
  56:   end
  57: 
  58:   // Data path: fout_wdata
  59:   typedef enum logic [2:0] {
  60:     FifoIn,         // fin_wdata, fin_wstrb
  61:     Pad80,          // {8'h80, 8'h00} , strb (calc based on len[4:3])
  62:     Pad00,          // 32'h0, full strb
  63:     LenHi,          // len[63:32], full strb
  64:     LenLo           // len[31:0], full strb
  65:   } sel_data_e;
  66:   sel_data_e sel_data;
  67: 
  68:   always_comb begin
  69:     unique case (sel_data)
  70:       FifoIn: begin
  71:         shaf_rdata = fifo_rdata.data;
  72:       end
  73: 
  74:       Pad80: begin
  75:         // {a[7:0], b[7:0], c[7:0], d[7:0]}
  76:         // msglen[4:3] == 00 |-> {'h80, 'h00, 'h00, 'h00}
  77:         // msglen[4:3] == 01 |-> {msg,  'h80, 'h00, 'h00}
  78:         // msglen[4:3] == 10 |-> {msg[15:0],  'h80, 'h00}
  79:         // msglen[4:3] == 11 |-> {msg[23:0],        'h80}
  80:         unique case (message_length[4:3])
  81:           2'b 00: shaf_rdata = 32'h 8000_0000;
  82:           2'b 01: shaf_rdata = {fifo_rdata.data[31:24], 24'h 8000_00};
  83:           2'b 10: shaf_rdata = {fifo_rdata.data[31:16], 16'h 8000};
  84:           2'b 11: shaf_rdata = {fifo_rdata.data[31: 8],  8'h 80};
  85:           default: shaf_rdata = 32'h0;
  86:         endcase
  87:       end
  88: 
  89:       Pad00: begin
  90:         shaf_rdata = '0;
  91:       end
  92: 
  93:       LenHi: begin
  94:         shaf_rdata = message_length[63:32];
  95:       end
  96: 
  97:       LenLo: begin
  98:         shaf_rdata = message_length[31:0];
  99:       end
 100: 
 101:       default: begin
 102:         shaf_rdata = '0;
 103:       end
 104:     endcase
 105:   end
 106: 
 107:   // Padded length
 108:   // $ceil(message_length + 8 + 64, 512) -> message_length [8:0] + 440 and ignore carry
 109:   //assign length_added = (message_length[8:0] + 9'h1b8) ;
 110: 
 111:   // fifo control
 112:   // add 8'h 80 , N 8'h00, 64'h message_length
 113: 
 114:   // Steps
 115:   // 1. `hash_start` from CPU (or DMA?)
 116:   // 2. calculate `padded_length` from `message_length`
 117:   // 3. Check if tx_count == message_length, then go to 5
 118:   // 4. Receiving FIFO input (hand over to fifo output)
 119:   // 5. Padding bit 1 (8'h80) followed by 8'h00 if needed
 120:   // 6. Padding with length (high -> low)
 121: 
 122:   // State Machine
 123:   typedef enum logic [2:0] {
 124:     StIdle,        // fin_full to prevent unwanted FIFO write
 125:     StFifoReceive, // Check tx_count == message_length
 126:     StPad80,       // 8'h 80 + 8'h 00 X N
 127:     StPad00,
 128:     StLenHi,
 129:     StLenLo
 130:   } pad_st_e;
 131: 
 132:   pad_st_e st_q, st_d;
 133: 
 134:   always_ff @(posedge clk_i or negedge rst_ni) begin
 135:     if (!rst_ni) begin
 136:       st_q <= StIdle;
 137:     end else begin
 138:       st_q <= st_d;
 139:     end
 140:   end
 141: 
 142:   // Next state
 143:   always_comb begin
 144:     shaf_rvalid = 1'b0;
 145:     inc_txcount = 1'b0;
 146:     sel_data = FifoIn;
 147:     fifo_rready = 1'b0;
 148: 
 149:     st_d = StIdle;
 150: 
 151:     unique case (st_q)
 152:       StIdle: begin
 153:         sel_data = FifoIn;
 154:         shaf_rvalid = 1'b0;
 155: 
 156:         if (sha_en && hash_start) begin
 157:           inc_txcount = 1'b0;
 158: 
 159:           st_d = StFifoReceive;
 160:         end else begin
 161:           st_d = StIdle;
 162:         end
 163:       end
 164: 
 165:       StFifoReceive: begin
 166:         sel_data = FifoIn;
 167: 
 168:         if (fifo_partial && fifo_rvalid) begin
 169:           // End of the message, assume hash_process_flag is set
 170:           shaf_rvalid  = 1'b0; // Update entry at StPad80
 171:           inc_txcount = 1'b0;
 172:           fifo_rready = 1'b0;
 173: 
 174:           st_d = StPad80;
 175:         end else if (!hash_process_flag) begin
 176:           fifo_rready = shaf_rready;
 177:           shaf_rvalid  = fifo_rvalid;
 178:           inc_txcount = shaf_rready;
 179: 
 180:           st_d = StFifoReceive;
 181:         end else if (tx_count == message_length) begin
 182:           // already received all msg and was waiting process flag
 183:           shaf_rvalid  = 1'b0;
 184:           inc_txcount = 1'b0;
 185:           fifo_rready = 1'b0;
 186: 
 187:           st_d = StPad80;
 188:         end else begin
 189:           shaf_rvalid  = fifo_rvalid;
 190:           fifo_rready = shaf_rready; // 0 always
 191:           inc_txcount = shaf_rready; // 0 always
 192: 
 193:           st_d = StFifoReceive;
 194:         end
 195:       end
 196: 
 197:       StPad80: begin
 198:         sel_data = Pad80;
 199: 
 200:         shaf_rvalid = 1'b1;
 201:         fifo_rready = shaf_rready && |message_length[4:3]; // Only when partial
 202: 
 203:         // exactly 96 bits left, do not need to pad00's
 204:         if (shaf_rready && txcnt_eq_1a0) begin
 205:           st_d = StLenHi;
 206:           inc_txcount = 1'b1;
 207:         // it does not matter if value is < or > than 416 bits.  If it's the former, 00 pad until
 208:         // length field.  If >, then the next chunk will contain the length field with appropriate
 209:         // 0 padding.
 210:         end else if (shaf_rready && !txcnt_eq_1a0) begin
 211:           st_d = StPad00;
 212:           inc_txcount = 1'b1;
 213:         end else begin
 214:           st_d = StPad80;
 215:           inc_txcount = 1'b0;
 216:         end
 217: 
 218:         // # Below part is temporal code to speed up the SHA by 16 clocks per chunk
 219:         // # (80 clk --> 64 clk)
 220:         // # leaving this as a reference but needs to verify it.
 221:         //if (shaf_rready && !txcnt_eq_1a0) begin
 222:         //  st_d = StPad00;
 223:         //
 224:         //  inc_txcount = 1'b1;
 225:         //  shaf_rvalid = (msg_word_aligned) ? 1'b1 : fifo_rvalid;
 226:         //  fifo_rready = (msg_word_aligned) ? 1'b0 : 1'b1;
 227:         //end else if (!shaf_rready && !txcnt_eq_1a0) begin
 228:         //  st_d = StPad80;
 229:         //
 230:         //  inc_txcount = 1'b0;
 231:         //  shaf_rvalid = (msg_word_aligned) ? 1'b1 : fifo_rvalid;
 232:         //
 233:         //end else if (shaf_rready && txcnt_eq_1a0) begin
 234:         //  st_d = StLenHi;
 235:         //  inc_txcount = 1'b1;
 236:         //end else begin
 237:         //  // !shaf_rready && txcnt_eq_1a0 , just wait until fifo_rready asserted
 238:         //  st_d = StPad80;
 239:         //  inc_txcount = 1'b0;
 240:         //end
 241:       end
 242: 
 243:       StPad00: begin
 244:         sel_data = Pad00;
 245:         shaf_rvalid = 1'b1;
 246: 
 247:         if (shaf_rready) begin
 248:           inc_txcount = 1'b1;
 249: 
 250:           if (txcnt_eq_1a0) begin
 251:             st_d = StLenHi;
 252:           end else begin
 253:             st_d = StPad00;
 254:           end
 255:         end else begin
 256:           st_d = StPad00;
 257:         end
 258:       end
 259: 
 260:       StLenHi: begin
 261:         sel_data = LenHi;
 262:         shaf_rvalid = 1'b1;
 263: 
 264:         if (shaf_rready) begin
 265:           st_d = StLenLo;
 266: 
 267:           inc_txcount = 1'b1;
 268:         end else begin
 269:           st_d = StLenHi;
 270: 
 271:           inc_txcount = 1'b0;
 272:         end
 273:       end
 274: 
 275:       StLenLo: begin
 276:         sel_data = LenLo;
 277:         shaf_rvalid = 1'b1;
 278: 
 279:         if (shaf_rready) begin
 280:           st_d = StIdle;
 281: 
 282:           inc_txcount = 1'b1;
 283:         end else begin
 284:           st_d = StLenLo;
 285: 
 286:           inc_txcount = 1'b0;
 287:         end
 288:       end
 289: 
 290:       default: begin
 291:         st_d = StIdle;
 292:       end
 293:     endcase
 294:   end
 295: 
 296:   // tx_count
 297:   always_ff @(posedge clk_i or negedge rst_ni) begin
 298:     if (!rst_ni) begin
 299:       tx_count <= '0;
 300:     end else if (hash_start) begin
 301:       tx_count <= '0;
 302:     end else if (inc_txcount) begin
 303:       tx_count[63:5] <= tx_count[63:5] + 1'b1;
 304:     end
 305:   end
 306: 
 307:   // State machine is in Idle only when it meets tx_count == message length
 308:   assign msg_feed_complete = hash_process_flag && (st_q == StIdle);
 309: 
 310:   // When fifo_partial, fifo shouldn't be empty and hash_process was set
 311:   `ASSERT(ValidPartialConditionAssert,
 312:           fifo_partial && fifo_rvalid |-> hash_process_flag,
 313:           clk_i, !rst_ni)
 314: 
 315: endmodule
 316: