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