../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: