hw/ip/hmac/rtl/sha2.sv Cov: 98.9%

   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 algorithm
   6: //
   7: 
   8: module sha2 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:   // FIFO read signal
  16:   input             fifo_rvalid,
  17:   input  sha_fifo_t fifo_rdata,
  18:   output logic      fifo_rready,
  19: 
  20:   // Control signals
  21:   input        sha_en,   // If disabled, it clears internal content.
  22:   input        hash_start,
  23:   input        hash_process,
  24:   output logic hash_done,
  25: 
  26:   input        [63:0] message_length,   // bits but byte based
  27:   output sha_word_t [7:0] digest
  28: );
  29: 
  30:   logic msg_feed_complete;
  31: 
  32:   logic      shaf_rready;
  33:   sha_word_t shaf_rdata;
  34:   logic      shaf_rvalid;
  35: 
  36:   logic [$clog2(NumRound)-1:0] round;
  37: 
  38:   logic      [3:0]  w_index;
  39:   sha_word_t [15:0] w;
  40: 
  41:   // w, hash, digest update logic control signals
  42:   logic update_w_from_fifo, calculate_next_w;
  43:   logic init_hash, run_hash, complete_one_chunk;
  44:   logic update_digest, clear_digest;
  45: 
  46:   logic hash_done_next; // to meet the phase with digest value.
  47: 
  48:   sha_word_t [7:0] hash;    // a,b,c,d,e,f,g,h
  49: 
  50:   // Fill up w
  51:   always_ff @(posedge clk_i or negedge rst_ni) begin : fill_w
  52:     if (!rst_ni) begin
  53:       w <= '0;
  54:     end else if (wipe_secret) begin
  55:       w <= w ^ {16{wipe_v}};
  56:     end else if (!sha_en) begin
  57:       w <= '0;
  58:     end else if (!run_hash && update_w_from_fifo) begin
  59:       // this logic runs at the first stage of SHA.
  60:       w <= {shaf_rdata, w[15:1]};
  61:     end else if (calculate_next_w) begin
  62:       w <= {calc_w(w[0], w[1], w[9], w[14]), w[15:1]};
  63:     //end else if (run_hash && update_w_from_fifo) begin
  64:     //  // This code runs when round is in [48, 63]. At this time, it reads from the fifo
  65:     //  // to fill the register if available. If FIFO goes to empty, w_index doesn't increase
  66:     //  // and it cannot reach 15. Then the sha engine doesn't start, which introduces latency.
  67:     //  //
  68:     //  // But in this case, still w should be shifted to feed SHA compress engine. Then
  69:     //  // fifo_rdata should be inserted in the middle of w index.
  70:     //  // w[64-round + w_index] <= fifo_rdata;
  71:     //  for (int i = 0 ; i < 16 ; i++) begin
  72:     //    if (i == (64 - round + w_index)) begin
  73:     //      w[i] <= shaf_rdata;
  74:     //    end else if (i == 15) begin
  75:     //      w[i] <= '0;
  76:     //    end else begin
  77:     //      w[i] <= w[i+1];
  78:     //    end
  79:     //  end
  80:     end else if (run_hash) begin
  81:       // Just shift-out. There's no incoming data
  82:       w <= {sha_word_t'(0), w[15:1]};
  83:     end
  84:   end : fill_w
  85: 
  86:   // Update engine
  87:   always_ff @(posedge clk_i or negedge rst_ni) begin : compress_round
  88:     if (!rst_ni) begin
  89:       hash <= '{default:'0};
  90:     end else if (wipe_secret) begin
  91:       for (int i = 0 ; i < 8 ; i++) begin
  92:         hash[i] <= hash[i] ^ wipe_v;
  93:       end
  94:     end else if (init_hash) begin
  95:       hash <= digest;
  96:     end else if (run_hash) begin
  97:       hash <= compress( w[0], CubicRootPrime[round], hash);
  98:     end
  99:   end : compress_round
 100: 
 101:   // Digest
 102:   always_ff @(posedge clk_i or negedge rst_ni) begin
 103:     if (!rst_ni) begin
 104:       digest <= '{default: '0};
 105:     end else if (wipe_secret) begin
 106:       for (int i = 0 ; i < 8 ; i++) begin
 107:         digest[i] <= digest[i] ^ wipe_v;
 108:       end
 109:     end else if (hash_start) begin
 110:       for (int i = 0 ; i < 8 ; i++) begin
 111:         digest[i] <= InitHash[i];
 112:       end
 113:     end else if (!sha_en || clear_digest) begin
 114:       digest <= '0;
 115:     end else if (update_digest) begin
 116:       for (int i = 0 ; i < 8 ; i++) begin
 117:         digest[i] <= digest[i] + hash[i];
 118:       end
 119:     end
 120:   end
 121: 
 122:   // round
 123:   always_ff @(posedge clk_i or negedge rst_ni) begin
 124:     if (!rst_ni) begin
 125:       round <= '0;
 126:     end else if (!sha_en) begin
 127:       round <= '0;
 128:     end else if (run_hash) begin
 129:       if (round == (NumRound-1)) begin
 130:         round <= '0;
 131:       end else begin
 132:         round <= round + 1;
 133:       end
 134:     end
 135:   end
 136: 
 137:   // w_index
 138:   always_ff @(posedge clk_i or negedge rst_ni) begin
 139:     if (!rst_ni) begin
 140:       w_index <= '0;
 141:     end else if (!sha_en) begin
 142:       w_index <= '0;
 143:     end else if (update_w_from_fifo) begin
 144:       w_index <= w_index + 1;
 145:     end
 146:   end
 147: 
 148:   assign shaf_rready = update_w_from_fifo;
 149: 
 150:   always_ff @(posedge clk_i or negedge rst_ni) begin
 151:     if (!rst_ni) hash_done <= 1'b0;
 152:     else         hash_done <= hash_done_next;
 153:   end
 154: 
 155:   typedef enum logic [1:0] {
 156:     FifoIdle,
 157:     FifoLoadFromFifo,
 158:     FifoWait
 159:   } fifoctl_state_e;
 160: 
 161:   fifoctl_state_e fifo_st_q, fifo_st_d;
 162: 
 163:   always_ff @(posedge clk_i or negedge rst_ni) begin
 164:     if (!rst_ni) begin
 165:       fifo_st_q <= FifoIdle;
 166:     end else begin
 167:       fifo_st_q <= fifo_st_d;
 168:     end
 169:   end
 170: 
 171:   always_comb begin
 172:     fifo_st_d = FifoIdle;
 173:     update_w_from_fifo = 1'b0;
 174:     hash_done_next = 1'b0;
 175: 
 176:     unique case (fifo_st_q)
 177:       FifoIdle: begin
 178:         if (hash_start) begin
 179:           fifo_st_d = FifoLoadFromFifo;
 180:         end else begin
 181:           fifo_st_d = FifoIdle;
 182:         end
 183:       end
 184: 
 185:       FifoLoadFromFifo: begin
 186:         if (!sha_en) begin
 187:           fifo_st_d = FifoIdle;
 188:           update_w_from_fifo = 1'b0;
 189:         end else if (!shaf_rvalid) begin
 190:           // Wait until it is filled
 191:           fifo_st_d = FifoLoadFromFifo;
 192:           update_w_from_fifo = 1'b0;
 193:         end else if (w_index == 4'd 15) begin
 194:           fifo_st_d = FifoWait;
 195:           update_w_from_fifo = 1'b1;
 196:         end else begin
 197:           fifo_st_d = FifoLoadFromFifo;
 198:           update_w_from_fifo = 1'b1;
 199:         end
 200:       end
 201: 
 202:       FifoWait: begin
 203:         // Wait until next fetch begins (begin at round == 48)a
 204:         if (msg_feed_complete && complete_one_chunk) begin
 205:           fifo_st_d = FifoIdle;
 206: 
 207:           hash_done_next = 1'b1;
 208:         end else if (complete_one_chunk) begin
 209:           fifo_st_d = FifoLoadFromFifo;
 210:         end else begin
 211:           fifo_st_d = FifoWait;
 212:         end
 213:       end
 214: 
 215:       default: begin
 216:         fifo_st_d = FifoIdle;
 217:       end
 218:     endcase
 219:   end
 220: 
 221:   // SHA control
 222:   typedef enum logic [1:0] {
 223:     ShaIdle,
 224:     ShaCompress,
 225:     ShaUpdateDigest
 226:   } sha_st_t;
 227: 
 228:   sha_st_t sha_st_q, sha_st_d;
 229: 
 230:   always_ff @(posedge clk_i or negedge rst_ni) begin
 231:     if (!rst_ni) begin
 232:       sha_st_q <= ShaIdle;
 233:     end else begin
 234:       sha_st_q <= sha_st_d;
 235:     end
 236:   end
 237: 
 238:   assign clear_digest = hash_start;
 239: 
 240:   always_comb begin
 241:     update_digest    = 1'b0;
 242:     calculate_next_w = 1'b0;
 243: 
 244:     init_hash        = 1'b0;
 245:     run_hash         = 1'b0;
 246: 
 247:     unique case (sha_st_q)
 248:       ShaIdle: begin
 249:         if (fifo_st_q == FifoWait) begin
 250:           init_hash = 1'b1;
 251:           sha_st_d = ShaCompress;
 252:         end else begin
 253:           sha_st_d = ShaIdle;
 254:         end
 255:       end
 256: 
 257:       ShaCompress: begin
 258:         run_hash = 1'b1;
 259: 
 260:         if (round < 48) begin
 261:           calculate_next_w = 1'b1;
 262:         end
 263: 
 264:         if (complete_one_chunk) begin
 265:           sha_st_d = ShaUpdateDigest;
 266:         end else begin
 267:           sha_st_d = ShaCompress;
 268:         end
 269:       end
 270: 
 271:       ShaUpdateDigest: begin
 272:         update_digest = 1'b1;
 273:         if (fifo_st_q == FifoWait) begin
 274:           init_hash = 1'b1;
 275:           sha_st_d = ShaCompress;
 276:         end else begin
 277:           sha_st_d = ShaIdle;
 278:         end
 279:       end
 280: 
 281:       default: begin
 282:         sha_st_d = ShaIdle;
 283:       end
 284:     endcase
 285:   end
 286: 
 287:   // complete_one_chunk
 288:   assign complete_one_chunk = (round == 6'd63);
 289: 
 290:   sha2_pad u_pad (
 291:     .clk_i,
 292:     .rst_ni,
 293: 
 294:     .wipe_secret,
 295:     .wipe_v,
 296: 
 297:     .fifo_rvalid,
 298:     .fifo_rdata,
 299:     .fifo_rready,
 300: 
 301:     .shaf_rvalid,
 302:     .shaf_rdata,
 303:     .shaf_rready,
 304: 
 305:     .sha_en,
 306:     .hash_start,
 307:     .hash_process,
 308:     .hash_done,
 309: 
 310:     .message_length,
 311:     .msg_feed_complete
 312:   );
 313: 
 314: 
 315: endmodule : sha2
 316: