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