hw/ip/aes/rtl/aes_key_expand.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: // AES KeyExpand
   6: 
   7: module aes_key_expand #(
   8:   parameter bit AES192Enable = 1,
   9:   parameter     SBoxImpl     = "lut"
  10: ) (
  11:   input  logic              clk_i,
  12:   input  logic              rst_ni,
  13:   input  aes_pkg::mode_e    mode_i,
  14:   input  logic              step_i,
  15:   input  logic              clear_i,
  16:   input  logic        [3:0] round_i,
  17:   input  aes_pkg::key_len_e key_len_i,
  18:   input  logic  [7:0][31:0] key_i,
  19:   output logic  [7:0][31:0] key_o
  20: );
  21: 
  22:   import aes_pkg::*;
  23: 
  24:   logic       [7:0] rcon_d, rcon_q;
  25:   logic             rcon_we;
  26:   logic             use_rcon;
  27: 
  28:   logic       [3:0] rnd;
  29:   logic       [3:0] rnd_type;
  30: 
  31:   logic      [31:0] spec_in_128, spec_in_192;
  32:   logic      [31:0] rot_word_in, rot_word_out;
  33:   logic             use_rot_word;
  34:   logic      [31:0] sub_word_in, sub_word_out;
  35:   logic       [7:0] rcon_add_in, rcon_add_out;
  36:   logic      [31:0] rcon_added;
  37: 
  38:   logic      [31:0] irregular;
  39:   logic [7:0][31:0] regular;
  40: 
  41:   assign rnd = round_i;
  42: 
  43:   // For AES-192, there are four different types of rounds.
  44:   always_comb begin : get_rnd_type
  45:     if (AES192Enable) begin
  46:       rnd_type[0] = (rnd == 0);
  47:       rnd_type[1] = (rnd == 1 || rnd == 4 || rnd == 7 || rnd == 10);
  48:       rnd_type[2] = (rnd == 2 || rnd == 5 || rnd == 8 || rnd == 11);
  49:       rnd_type[3] = (rnd == 3 || rnd == 6 || rnd == 9 || rnd == 12);
  50:     end else begin
  51:       rnd_type = '0;
  52:     end
  53:   end
  54: 
  55:   //////////////////////////////////////////////////////
  56:   // Irregular part involving Rcon, RotWord & SubWord //
  57:   //////////////////////////////////////////////////////
  58: 
  59:   // Depending on key length and round, RotWord is not used
  60:   assign use_rot_word = (key_len_i == AES_256 && rnd[0] == 1'b0) ? 1'b0 : 1'b1;
  61: 
  62:   // Depending on mode, key length and round, Rcon is not used and thus must not be updated
  63:   always_comb begin : rcon_usage
  64:     use_rcon = 1'b1;
  65: 
  66:     if (AES192Enable) begin
  67:       if (key_len_i == AES_192 &&
  68:           ((mode_i == AES_ENC &&  rnd_type[1]) ||
  69:            (mode_i == AES_DEC && (rnd_type[0] || rnd_type[3])))) begin
  70:         use_rcon = 1'b0;
  71:       end
  72:     end
  73: 
  74:     if (key_len_i == AES_256 && rnd[0] == 1'b0) begin
  75:       use_rcon = 1'b0;
  76:     end
  77:   end
  78: 
  79:   // Generate Rcon
  80:   always_comb begin : rcon_update
  81:     rcon_d = rcon_q;
  82: 
  83:     if (clear_i) begin
  84:       rcon_d =  (mode_i == AES_ENC)                            ? 8'h01 :
  85:                ((mode_i == AES_DEC) && (key_len_i == AES_128)) ? 8'h36 :
  86:                ((mode_i == AES_DEC) && (key_len_i == AES_192)) ? 8'h80 :
  87:                ((mode_i == AES_DEC) && (key_len_i == AES_256)) ? 8'h40 : 8'h01;
  88:     end else begin
  89:       rcon_d =  (mode_i == AES_ENC) ? aes_mul2(rcon_q) :
  90:                 (mode_i == AES_DEC) ? aes_div2(rcon_q) : 8'h01;
  91:     end
  92:   end
  93: 
  94:   assign rcon_we = clear_i | (step_i & use_rcon);
  95: 
  96:   // Rcon register
  97:   always_ff @(posedge clk_i or negedge rst_ni) begin : reg_rcon
  98:     if (!rst_ni) begin
  99:       rcon_q <= '0;
 100:     end else if (rcon_we) begin
 101:       rcon_q <= rcon_d;
 102:     end
 103:   end
 104: 
 105:   // Special input, equivalent to key_o[3] in the used cases
 106:   assign spec_in_128 = key_i[3] ^ key_i[2];
 107:   assign spec_in_192 = AES192Enable ? key_i[5] ^ key_i[1] ^ key_i[0] : '0;
 108: 
 109:   // Select input
 110:   always_comb begin : rot_word_in_mux
 111:     unique case (key_len_i)
 112: 
 113:       /////////////
 114:       // AES-128 //
 115:       /////////////
 116:       AES_128: begin
 117:         unique case (mode_i)
 118:           AES_ENC: rot_word_in = key_i[3];
 119:           AES_DEC: rot_word_in = spec_in_128;
 120:           default: rot_word_in = key_i[3];
 121:         endcase
 122:       end
 123: 
 124:       /////////////
 125:       // AES-192 //
 126:       /////////////
 127:       AES_192: begin
 128:         if (AES192Enable) begin
 129:           unique case (mode_i)
 130:             AES_ENC: begin
 131:               rot_word_in = rnd_type[0] ? key_i[5]    :
 132:                             rnd_type[2] ? key_i[5]    :
 133:                             rnd_type[3] ? spec_in_192 : key_i[3];
 134:             end
 135:             AES_DEC: begin
 136:               rot_word_in = rnd_type[1] ? key_i[3] :
 137:                             rnd_type[2] ? key_i[1] : key_i[3];
 138:             end
 139:             default: rot_word_in = key_i[3];
 140:           endcase
 141:         end else begin
 142:           rot_word_in = key_i[3];
 143:         end
 144:       end
 145: 
 146:       /////////////
 147:       // AES-256 //
 148:       /////////////
 149:       AES_256: begin
 150:         unique case (mode_i)
 151:           AES_ENC: rot_word_in = key_i[7];
 152:           AES_DEC: rot_word_in = key_i[3];
 153:           default: rot_word_in = key_i[7];
 154:         endcase
 155:       end
 156: 
 157:       default: rot_word_in = key_i[3];
 158:     endcase
 159:   end
 160: 
 161:   // RotWord: cyclic byte shift
 162:   assign rot_word_out = aes_circ_byte_shift(rot_word_in, 3);
 163: 
 164:   // Mux input for SubWord
 165:   assign sub_word_in = use_rot_word ? rot_word_out : rot_word_in;
 166: 
 167:   // SubWord - individually substitute bytes
 168:   for (genvar i = 0; i < 4; i++) begin : gen_sbox
 169:     aes_sbox #(
 170:       .SBoxImpl ( SBoxImpl )
 171:     ) aes_sbox_i (
 172:       .mode_i ( AES_ENC   ),
 173:       .data_i ( sub_word_in[8*i +: 8]  ),
 174:       .data_o ( sub_word_out[8*i +: 8] )
 175:     );
 176:   end
 177: 
 178:   // Add Rcon
 179:   assign rcon_add_in  = sub_word_out[7:0];
 180:   assign rcon_add_out = rcon_add_in ^ rcon_q;
 181:   assign rcon_added   = {sub_word_out[31:8], rcon_add_out};
 182: 
 183:   // Mux output coming from Rcon & SubWord
 184:   assign irregular = use_rcon ? rcon_added : sub_word_out;
 185: 
 186:   ///////////////////////////
 187:   // The more regular part //
 188:   ///////////////////////////
 189: 
 190:   // To reduce muxing resources, we re-use existing
 191:   // connections for unused words and default cases.
 192:   always_comb begin : drive_regular
 193:     unique case (key_len_i)
 194: 
 195:       /////////////
 196:       // AES-128 //
 197:       /////////////
 198:       AES_128: begin
 199:         // key_o[7:4] not used
 200:         regular[7:4] = key_i[3:0];
 201: 
 202:         regular[0] = irregular ^ key_i[0];
 203:         unique case (mode_i)
 204:           AES_ENC: begin
 205:             for (int i=1; i<4; i++) begin
 206:               regular[i] = regular[i-1] ^ key_i[i];
 207:             end
 208:           end
 209: 
 210:           AES_DEC: begin
 211:             for (int i=1; i<4; i++) begin
 212:               regular[i] = key_i[i-1] ^ key_i[i];
 213:             end
 214:           end
 215: 
 216:           default: regular = {key_i[3:0], key_i[7:4]};
 217:         endcase
 218:       end
 219: 
 220:       /////////////
 221:       // AES-192 //
 222:       /////////////
 223:       AES_192: begin
 224:         // key_o[7:6] not used
 225:         regular[7:6] = key_i[3:2];
 226: 
 227:         if (AES192Enable) begin
 228:           unique case (mode_i)
 229:             AES_ENC: begin
 230:               if (rnd_type[0]) begin
 231:                 // Shift down four upper most words
 232:                 regular[3:0] = key_i[5:2];
 233:                 // Generate Words 6 and 7
 234:                 regular[4]   = irregular  ^ key_i[0];
 235:                 regular[5]   = regular[4] ^ key_i[1];
 236:               end else begin
 237:                 // Shift down two upper most words
 238:                 regular[1:0] = key_i[5:4];
 239:                 // Generate new upper four words
 240:                 for (int i=0; i<4; i++) begin
 241:                   if ((i == 0 && rnd_type[2]) ||
 242:                       (i == 2 && rnd_type[3])) begin
 243:                     regular[i+2] = irregular    ^ key_i[i];
 244:                   end else begin
 245:                     regular[i+2] = regular[i+1] ^ key_i[i];
 246:                   end
 247:                 end
 248:               end // rnd_type[0]
 249:             end
 250: 
 251:             AES_DEC: begin
 252:               if (rnd_type[0]) begin
 253:                 // Shift up four lowest words
 254:                 regular[5:2] = key_i[3:0];
 255:                 // Generate Word 44 and 45
 256:                 for (int i=0; i<2; i++) begin
 257:                   regular[i] = key_i[3+i] ^ key_i[3+i+1];
 258:                 end
 259:               end else begin
 260:                 // Shift up two lowest words
 261:                 regular[5:4] = key_i[1:0];
 262:                 // Generate new lower four words
 263:                 for (int i=0; i<4; i++) begin
 264:                   if ((i == 2 && rnd_type[1]) ||
 265:                       (i == 0 && rnd_type[2])) begin
 266:                     regular[i] = irregular  ^ key_i[i+2];
 267:                   end else begin
 268:                     regular[i] = key_i[i+1] ^ key_i[i+2];
 269:                   end
 270:                 end
 271:               end // rnd_type[0]
 272:             end
 273: 
 274:             default: regular = {key_i[3:0], key_i[7:4]};
 275:           endcase
 276: 
 277:         end else begin
 278:           regular = {key_i[3:0], key_i[7:4]};
 279:         end // AES192Enable
 280:       end
 281: 
 282:       /////////////
 283:       // AES-256 //
 284:       /////////////
 285:       AES_256: begin
 286:         unique case (mode_i)
 287:           AES_ENC: begin
 288:             if (rnd == 0) begin
 289:               // Round 0: Nothing to be done
 290:               // The Full Key registers are not updated
 291:               regular = {key_i[3:0], key_i[7:4]};
 292:             end else begin
 293:               // Shift down old upper half
 294:               regular[3:0] = key_i[7:4];
 295:               // Generate new upper half
 296:               regular[4]   = irregular ^ key_i[0];
 297:               for (int i=1; i<4; i++) begin
 298:                 regular[i+4] = regular[i+4-1] ^ key_i[i];
 299:               end
 300:             end // rnd == 0
 301:           end
 302: 
 303:           AES_DEC: begin
 304:             if (rnd == 0) begin
 305:               // Round 0: Nothing to be done
 306:               // The Full Key registers are not updated
 307:               regular = {key_i[3:0], key_i[7:4]};
 308:             end else begin
 309:               // Shift up old lower half
 310:               regular[7:4] = key_i[3:0];
 311:               // Generate new lower half
 312:               regular[0]   = irregular ^ key_i[4];
 313:               for (int i=0; i<3; i++) begin
 314:                 regular[i+1] = key_i[4+i] ^ key_i[4+i+1];
 315:               end
 316:             end // rnd == 0
 317:           end
 318: 
 319:           default: regular = {key_i[3:0], key_i[7:4]};
 320:         endcase
 321:       end
 322: 
 323:       default: regular = {key_i[3:0], key_i[7:4]};
 324:     endcase // key_len_i
 325:   end
 326: 
 327:   // Drive output
 328:   assign key_o = regular;
 329: 
 330:   // Selectors must be known/valid
 331:   `ASSERT_KNOWN(AesModeKnown, mode_i, clk_i, !rst_ni)
 332:   `ASSERT(AesKeyLenValid, key_len_i inside {
 333:       AES_128,
 334:       AES_192,
 335:       AES_256
 336:       }, clk_i, !rst_ni)
 337: 
 338: endmodule
 339: