hw/ip/hmac/rtl/hmac_core.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: // HMAC Core implementation
   6: 
   7: module hmac_core import hmac_pkg::*; (
   8:   input clk_i,
   9:   input rst_ni,
  10: 
  11:   input [255:0] secret_key, // {word0, word1, ..., word7}
  12: 
  13:   input        wipe_secret,
  14:   input [31:0] wipe_v,
  15: 
  16:   input        hmac_en,
  17: 
  18:   input        reg_hash_start,
  19:   input        reg_hash_process,
  20:   output logic hash_done,
  21:   output logic sha_hash_start,
  22:   output logic sha_hash_process,
  23:   input        sha_hash_done,
  24: 
  25:   // fifo
  26:   output logic      sha_rvalid,
  27:   output sha_fifo_t sha_rdata,
  28:   input             sha_rready,
  29: 
  30:   input             fifo_rvalid,
  31:   input  sha_fifo_t fifo_rdata,
  32:   output logic      fifo_rready,
  33: 
  34:   // fifo control (select and fifo write data)
  35:   output logic       fifo_wsel,    // 0: from reg, 1: from digest
  36:   output logic       fifo_wvalid,
  37:   output logic [2:0] fifo_wdata_sel, // 0: digest[0] .. 7: digest[7]
  38:   input              fifo_wready,
  39: 
  40:   input  [63:0] message_length,
  41:   output [63:0] sha_message_length
  42: );
  43: 
  44:   localparam int unsigned BlockSize = 512;
  45:   localparam int unsigned BlockSizeBits = $clog2(BlockSize);
  46:   localparam int unsigned HashWordBits = $clog2($bits(sha_word_t));
  47: 
  48:   logic hash_start; // generated from internal state machine
  49:   logic hash_process; // generated from internal state machine to trigger hash
  50:   logic hmac_hash_done;
  51: 
  52:   logic [BlockSize-1:0] i_pad ;
  53:   logic [BlockSize-1:0] o_pad ;
  54: 
  55:   logic [63:0] txcount;
  56:   logic [BlockSizeBits-HashWordBits-1:0] pad_index;
  57:   logic clr_txcount, inc_txcount;
  58: 
  59:   logic hmac_sha_rvalid;
  60: 
  61:   typedef enum logic [1:0] {
  62:     SelIPad,
  63:     SelOPad,
  64:     SelFifo
  65:   } sel_rdata_t;
  66: 
  67:   sel_rdata_t sel_rdata;
  68: 
  69:   typedef enum logic {
  70:     SelIPadMsg,
  71:     SelOPadMsg
  72:   } sel_msglen_t;
  73: 
  74:   sel_msglen_t sel_msglen;
  75: 
  76:   typedef enum logic {
  77:     Inner,  // Update when state goes to StIPad
  78:     Outer   // Update when state enters StOPad
  79:   } round_t ;
  80: 
  81:   logic update_round ;
  82:   round_t round_q, round_d;
  83: 
  84:   typedef enum logic [2:0] {
  85:     StIdle,
  86:     StIPad,
  87:     StMsg,              // Actual Msg, and Digest both
  88:     StPushToMsgFifo,    // Digest --> Msg Fifo
  89:     StWaitResp,         // Hash done( by checking processed_length? or hash_done)
  90:     StOPad,
  91:     StDone              // hmac_done
  92:   } st_e ;
  93: 
  94:   st_e st_q, st_d;
  95: 
  96:   logic clr_fifo_wdata_sel;
  97:   logic txcnt_eq_blksz ;
  98: 
  99:   logic reg_hash_process_flag;
 100: 
 101:   assign sha_hash_start   = (hmac_en) ? hash_start                       : reg_hash_start ;
 102:   assign sha_hash_process = (hmac_en) ? reg_hash_process | hash_process  : reg_hash_process ;
 103:   assign hash_done        = (hmac_en) ? hmac_hash_done                   : sha_hash_done  ;
 104: 
 105:   assign pad_index = txcount[BlockSizeBits-1:HashWordBits];
 106: 
 107:   assign i_pad = {secret_key, {(BlockSize-256){1'b0}}} ^ {(BlockSize/8){8'h36}};
 108:   assign o_pad = {secret_key, {(BlockSize-256){1'b0}}} ^ {(BlockSize/8){8'h5c}};
 109: 
 110: 
 111:   assign fifo_rready  = (hmac_en) ? (st_q == StMsg) & sha_rready : sha_rready ;
 112:   // sha_rvalid is controlled by State Machine below.
 113:   assign sha_rvalid = (!hmac_en) ? fifo_rvalid : hmac_sha_rvalid ;
 114:   assign sha_rdata =
 115:     (!hmac_en)             ? fifo_rdata                                               :
 116:     (sel_rdata == SelIPad) ? '{data: i_pad[(BlockSize-1)-32*pad_index-:32], mask: '1} :
 117:     (sel_rdata == SelOPad) ? '{data: o_pad[(BlockSize-1)-32*pad_index-:32], mask: '1} :
 118:     (sel_rdata == SelFifo) ? fifo_rdata                                               :
 119:     '{default: '0};
 120: 
 121:   assign sha_message_length = (!hmac_en)                 ? message_length             :
 122:                               (sel_msglen == SelIPadMsg) ? message_length + BlockSize :
 123:                               (sel_msglen == SelOPadMsg) ? BlockSize + 256            :
 124:                               '0 ;
 125: 
 126:   assign txcnt_eq_blksz = (txcount[BlockSizeBits:0] == BlockSize);
 127: 
 128:   assign inc_txcount = sha_rready && sha_rvalid;
 129: 
 130:   // txcount
 131:   //    Looks like txcount can be removed entirely here in hmac_core
 132:   //    In the first round (InnerPaddedKey), it can just watch process and hash_done
 133:   //    In the second round, it only needs count 256 bits for hash digest to trigger
 134:   //    hash_process to SHA2
 135:   always_ff @(posedge clk_i or negedge rst_ni) begin
 136:     if (!rst_ni) begin
 137:       txcount <= '0;
 138:     end else if (clr_txcount) begin
 139:       txcount <= '0;
 140:     end else if (inc_txcount) begin
 141:       txcount[63:5] <= txcount[63:5] + 1'b1;
 142:     end
 143:   end
 144: 
 145:   // reg_hash_process trigger logic
 146:   always_ff @(posedge clk_i or negedge rst_ni) begin
 147:     if (!rst_ni) begin
 148:       reg_hash_process_flag <= 1'b0;
 149:     end else if (reg_hash_process) begin
 150:       reg_hash_process_flag <= 1'b1;
 151:     end else if (hmac_hash_done || reg_hash_start) begin
 152:       reg_hash_process_flag <= 1'b0;
 153:     end
 154:   end
 155: 
 156:   always_ff @(posedge clk_i or negedge rst_ni) begin
 157:     if (!rst_ni) begin
 158:       round_q <= Inner;
 159:     end else if (update_round) begin
 160:       round_q <= round_d;
 161:     end
 162:   end
 163: 
 164:   always_ff @(posedge clk_i or negedge rst_ni) begin
 165:     if (!rst_ni) begin
 166:       fifo_wdata_sel <= 3'h 0;
 167:     end else if (clr_fifo_wdata_sel) begin
 168:       fifo_wdata_sel <= 3'h 0;
 169:     end else if (fifo_wsel && fifo_wvalid) begin
 170:       fifo_wdata_sel <= fifo_wdata_sel + 1'b1;
 171:     end
 172:   end
 173: 
 174:   assign sel_msglen = (round_q == Inner) ? SelIPadMsg : SelOPadMsg ;
 175: 
 176:   always_ff @(posedge clk_i or negedge rst_ni) begin : state_ff
 177:     if (!rst_ni) st_q <= StIdle;
 178:     else         st_q <= st_d;
 179:   end
 180: 
 181:   always_comb begin : next_state
 182:     hmac_hash_done  = 1'b0;
 183:     hmac_sha_rvalid = 1'b0;
 184: 
 185:     clr_txcount = 1'b0;
 186: 
 187:     update_round = 1'b0;
 188:     round_d      = Inner;
 189: 
 190:     fifo_wsel    = 1'b0;   // from register
 191:     fifo_wvalid  = 1'b0;
 192: 
 193:     clr_fifo_wdata_sel = 1'b1;
 194: 
 195:     sel_rdata = SelFifo;
 196: 
 197:     hash_start   = 1'b0;
 198:     hash_process = 1'b0;
 199: 
 200:     unique case (st_q)
 201:       StIdle: begin
 202:         if (hmac_en && reg_hash_start) begin
 203:           st_d = StIPad;
 204: 
 205:           clr_txcount  = 1'b1;
 206:           update_round = 1'b1;
 207:           round_d      = Inner;
 208:           hash_start   = 1'b1;
 209:         end else begin
 210:           st_d = StIdle;
 211:         end
 212:       end
 213: 
 214:       StIPad: begin
 215:         sel_rdata = SelIPad;
 216: 
 217:         if (txcnt_eq_blksz) begin
 218:           st_d = StMsg;
 219: 
 220:           hmac_sha_rvalid = 1'b0; // block new read request
 221:         end else begin
 222:           st_d = StIPad;
 223: 
 224:           hmac_sha_rvalid = 1'b1;
 225:         end
 226:       end
 227: 
 228:       StMsg: begin
 229:         sel_rdata = SelFifo;
 230: 
 231:         if ( (((round_q == Inner) && reg_hash_process_flag) || (round_q == Outer))
 232:             && (txcount >= sha_message_length)) begin
 233:           st_d = StWaitResp;
 234: 
 235:           hmac_sha_rvalid = 1'b0; // block
 236:           hash_process = (round_q == Outer);
 237:         end else begin
 238:           st_d = StMsg;
 239: 
 240:           hmac_sha_rvalid = fifo_rvalid;
 241:         end
 242:       end
 243: 
 244:       StWaitResp: begin
 245:         hmac_sha_rvalid = 1'b0;
 246: 
 247:         if (sha_hash_done) begin
 248:           if (round_q == Outer) begin
 249:             st_d = StDone;
 250:           end else begin // round_q == Inner
 251:             st_d = StPushToMsgFifo;
 252:           end
 253:         end else begin
 254:           st_d = StWaitResp;
 255:         end
 256:       end
 257: 
 258:       StPushToMsgFifo: begin
 259:         hmac_sha_rvalid    = 1'b0;
 260:         fifo_wsel          = 1'b1;
 261:         fifo_wvalid        = 1'b1;
 262:         clr_fifo_wdata_sel = 1'b0;
 263: 
 264:         if (fifo_wready && fifo_wdata_sel == 3'h7) begin
 265:           st_d = StOPad;
 266: 
 267:           clr_txcount  = 1'b1;
 268:           update_round = 1'b1;
 269:           round_d      = Outer;
 270:           hash_start   = 1'b1;
 271:         end else begin
 272:           st_d = StPushToMsgFifo;
 273: 
 274:         end
 275:       end
 276: 
 277:       StOPad: begin
 278:         sel_rdata = SelOPad;
 279: 
 280:         if (txcnt_eq_blksz) begin
 281:           st_d = StMsg;
 282: 
 283:           hmac_sha_rvalid = 1'b0; // block new read request
 284:         end else begin
 285:           st_d = StOPad;
 286: 
 287:           hmac_sha_rvalid = 1'b1;
 288:         end
 289:       end
 290: 
 291:       StDone: begin
 292:         // raise interrupt (hash_done)
 293:         st_d = StIdle;
 294: 
 295:         hmac_hash_done = 1'b1;
 296:       end
 297: 
 298:       default: begin
 299:         st_d = StIdle;
 300:       end
 301: 
 302:     endcase
 303:   end
 304: endmodule
 305: