../src/lowrisc_ip_aes_0.6/rtl/aes_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: // AES core implementation
6:
7: `include "prim_assert.sv"
8:
9: module aes_core #(
10: parameter bit AES192Enable = 1,
11: parameter SBoxImpl = "lut"
12: ) (
13: input logic clk_i,
14: input logic rst_ni,
15:
16: // PRNG Interface
17: output logic prng_data_req_o,
18: input logic prng_data_ack_i,
19: input logic [63:0] prng_data_i,
20:
21: output logic prng_reseed_req_o,
22: input logic prng_reseed_ack_i,
23:
24: // Bus Interface
25: input aes_reg_pkg::aes_reg2hw_t reg2hw,
26: output aes_reg_pkg::aes_hw2reg_t hw2reg
27: );
28:
29: import aes_reg_pkg::*;
30: import aes_pkg::*;
31:
32: // Signals
33: logic ctrl_qe;
34: logic ctrl_we;
35: aes_op_e aes_op_d, aes_op_q;
36: aes_mode_e aes_mode;
37: aes_mode_e aes_mode_d, aes_mode_q;
38: ciph_op_e cipher_op;
39: key_len_e key_len;
40: key_len_e key_len_d, key_len_q;
41: logic manual_operation_q;
42:
43: logic [3:0][3:0][7:0] state_in;
44: si_sel_e state_in_sel;
45: logic [3:0][3:0][7:0] add_state_in;
46: add_si_sel_e add_state_in_sel;
47:
48: logic [3:0][3:0][7:0] state_init;
49: logic [3:0][3:0][7:0] state_done;
50:
51: logic [7:0][31:0] key_init;
52: logic [7:0] key_init_qe;
53: logic [7:0][31:0] key_init_d;
54: logic [7:0][31:0] key_init_q;
55: logic [7:0] key_init_we;
56: key_init_sel_e key_init_sel;
57:
58: logic [3:0][31:0] iv;
59: logic [3:0] iv_qe;
60: logic [7:0][15:0] iv_d;
61: logic [7:0][15:0] iv_q;
62: logic [7:0] iv_we;
63: iv_sel_e iv_sel;
64:
65: logic [7:0][15:0] ctr;
66: logic [7:0] ctr_we;
67: logic ctr_incr;
68: logic ctr_ready;
69:
70: logic [3:0][31:0] data_in_prev_d;
71: logic [3:0][31:0] data_in_prev_q;
72: logic data_in_prev_we;
73: dip_sel_e data_in_prev_sel;
74:
75: logic [3:0][31:0] data_in;
76: logic [3:0] data_in_qe;
77: logic data_in_we;
78:
79: logic [3:0][3:0][7:0] add_state_out;
80: add_so_sel_e add_state_out_sel;
81:
82: logic [3:0][31:0] data_out_d;
83: logic [3:0][31:0] data_out_q;
84: logic data_out_we;
85: logic [3:0] data_out_re;
86:
87: logic cipher_in_valid;
88: logic cipher_in_ready;
89: logic cipher_out_valid;
90: logic cipher_out_ready;
91: logic cipher_crypt;
92: logic cipher_crypt_busy;
93: logic cipher_dec_key_gen;
94: logic cipher_dec_key_gen_busy;
95: logic cipher_key_clear;
96: logic cipher_key_clear_busy;
97: logic cipher_data_out_clear;
98: logic cipher_data_out_clear_busy;
99:
100: // Unused signals
101: logic [3:0][31:0] unused_data_out_q;
102:
103: ////////////
104: // Inputs //
105: ////////////
106:
107: always_comb begin : key_init_get
108: for (int i=0; i<8; i++) begin
109: key_init[i] = reg2hw.key[i].q;
110: key_init_qe[i] = reg2hw.key[i].qe;
111: end
112: end
113:
114: always_comb begin : iv_get
115: for (int i=0; i<4; i++) begin
116: iv[i] = reg2hw.iv[i].q;
117: iv_qe[i] = reg2hw.iv[i].qe;
118: end
119: end
120:
121: always_comb begin : data_in_get
122: for (int i=0; i<4; i++) begin
123: data_in[i] = reg2hw.data_in[i].q;
124: data_in_qe[i] = reg2hw.data_in[i].qe;
125: end
126: end
127:
128: always_comb begin : data_out_get
129: for (int i=0; i<4; i++) begin
130: // data_out is actually hwo, but we need hrw for hwre
131: unused_data_out_q[i] = reg2hw.data_out[i].q;
132: data_out_re[i] = reg2hw.data_out[i].re;
133: end
134: end
135:
136: assign aes_op_d = aes_op_e'(reg2hw.ctrl.operation.q);
137:
138: assign aes_mode = aes_mode_e'(reg2hw.ctrl.mode.q);
139: always_comb begin : mode_get
140: unique case (aes_mode)
141: AES_ECB: aes_mode_d = AES_ECB;
142: AES_CBC: aes_mode_d = AES_CBC;
143: AES_CTR: aes_mode_d = AES_CTR;
144: default: aes_mode_d = AES_ECB; // unsupported values are mapped to AES_ECB
145: endcase
146: end
147:
148: assign key_len = key_len_e'(reg2hw.ctrl.key_len.q);
149: always_comb begin : key_len_get
150: unique case (key_len)
151: AES_128: key_len_d = AES_128;
152: AES_256: key_len_d = AES_256;
153: AES_192: key_len_d = AES192Enable ? AES_192 : AES_128;
154: default: key_len_d = AES_128; // unsupported values are mapped to AES_128
155: endcase
156: end
157:
158: assign ctrl_qe = reg2hw.ctrl.operation.qe & reg2hw.ctrl.mode.qe & reg2hw.ctrl.key_len.qe &
159: reg2hw.ctrl.manual_operation.qe;
160:
161: //////////////////////
162: // Key, IV and Data //
163: //////////////////////
164:
165: // Initial Key registers
166: always_comb begin : key_init_mux
167: unique case (key_init_sel)
168: KEY_INIT_INPUT: key_init_d = key_init;
169: KEY_INIT_CLEAR: key_init_d = {prng_data_i, prng_data_i, prng_data_i, prng_data_i};
170: default: key_init_d = {prng_data_i, prng_data_i, prng_data_i, prng_data_i};
171: endcase
172: end
173:
174: always_ff @(posedge clk_i) begin : key_init_reg
175: for (int i=0; i<8; i++) begin
176: if (key_init_we[i]) begin
177: key_init_q[i] <= key_init_d[i];
178: end
179: end
180: end
181:
182: // IV registers
183: always_comb begin : iv_mux
184: unique case (iv_sel)
185: IV_INPUT: iv_d = iv;
186: IV_DATA_OUT: iv_d = data_out_d;
187: IV_DATA_IN_PREV: iv_d = data_in_prev_q;
188: IV_CTR: iv_d = ctr;
189: IV_CLEAR: iv_d = {prng_data_i, prng_data_i};
190: default: iv_d = {prng_data_i, prng_data_i};
191: endcase
192: end
193:
194: always_ff @(posedge clk_i) begin : iv_reg
195: for (int i=0; i<8; i++) begin
196: if (iv_we[i]) begin
197: iv_q[i] <= iv_d[i];
198: end
199: end
200: end
201:
202: // Previous input data register
203: always_comb begin : data_in_prev_mux
204: unique case (data_in_prev_sel)
205: DIP_DATA_IN: data_in_prev_d = data_in;
206: DIP_CLEAR: data_in_prev_d = {prng_data_i, prng_data_i};
207: default: data_in_prev_d = {prng_data_i, prng_data_i};
208: endcase
209: end
210:
211: always_ff @(posedge clk_i) begin : data_in_prev_reg
212: if (data_in_prev_we) begin
213: data_in_prev_q <= data_in_prev_d;
214: end
215: end
216:
217: /////////////
218: // Counter //
219: /////////////
220:
221: aes_ctr aes_ctr (
222: .clk_i ( clk_i ),
223: .rst_ni ( rst_ni ),
224:
225: .incr_i ( ctr_incr ),
226: .ready_o ( ctr_ready ),
227:
228: .ctr_i ( iv_q ),
229: .ctr_o ( ctr ),
230: .ctr_we_o ( ctr_we )
231: );
232:
233: /////////////////
234: // Cipher Core //
235: /////////////////
236:
237: // Cipher core operation
238: assign cipher_op = (aes_mode_q == AES_ECB && aes_op_q == AES_ENC) ? CIPH_FWD :
239: (aes_mode_q == AES_ECB && aes_op_q == AES_DEC) ? CIPH_INV :
240: (aes_mode_q == AES_CBC && aes_op_q == AES_ENC) ? CIPH_FWD :
241: (aes_mode_q == AES_CBC && aes_op_q == AES_DEC) ? CIPH_INV :
242: (aes_mode_q == AES_CTR) ? CIPH_FWD : CIPH_FWD;
243:
244: // Mux for state input
245: always_comb begin : state_in_mux
246: unique case (state_in_sel)
247: SI_ZERO: state_in = '0;
248: SI_DATA: state_in = aes_transpose(data_in);
249: default: state_in = '0;
250: endcase
251: end
252:
253: // Mux for addition to state input
254: always_comb begin : add_state_in_mux
255: unique case (add_state_in_sel)
256: ADD_SI_ZERO: add_state_in = '0;
257: ADD_SI_IV: add_state_in = aes_transpose(iv_q);
258: default: add_state_in = '0;
259: endcase
260: end
261:
262: // Convert input data to state format (every input data word contains one state column)
263: assign state_init = state_in ^ add_state_in;
264:
265: // Cipher core
266: aes_cipher_core #(
267: .AES192Enable ( AES192Enable ),
268: .SBoxImpl ( SBoxImpl )
269: ) aes_cipher_core (
270: .clk_i ( clk_i ),
271: .rst_ni ( rst_ni ),
272:
273: .in_valid_i ( cipher_in_valid ),
274: .in_ready_o ( cipher_in_ready ),
275: .out_valid_o ( cipher_out_valid ),
276: .out_ready_i ( cipher_out_ready ),
277: .op_i ( cipher_op ),
278: .key_len_i ( key_len_q ),
279: .crypt_i ( cipher_crypt ),
280: .crypt_o ( cipher_crypt_busy ),
281: .dec_key_gen_i ( cipher_dec_key_gen ),
282: .dec_key_gen_o ( cipher_dec_key_gen_busy ),
283: .key_clear_i ( cipher_key_clear ),
284: .key_clear_o ( cipher_key_clear_busy ),
285: .data_out_clear_i ( cipher_data_out_clear ),
286: .data_out_clear_o ( cipher_data_out_clear_busy ),
287:
288: .prng_data_i ( prng_data_i ),
289:
290: .state_init_i ( state_init ),
291: .key_init_i ( key_init_q ),
292: .state_o ( state_done )
293: );
294:
295: // Mux for addition to state output
296: always_comb begin : add_state_out_mux
297: unique case (add_state_out_sel)
298: ADD_SO_ZERO: add_state_out = '0;
299: ADD_SO_IV: add_state_out = aes_transpose(iv_q);
300: ADD_SO_DIP: add_state_out = aes_transpose(data_in_prev_q);
301: default: add_state_out = '0;
302: endcase
303: end
304:
305: // Convert output state to output data format (every state column corresponds to one output word)
306: assign data_out_d = aes_transpose(state_done ^ add_state_out);
307:
308: /////////////
309: // Control //
310: /////////////
311:
312: // Control
313: aes_control aes_control (
314: .clk_i ( clk_i ),
315: .rst_ni ( rst_ni ),
316:
317: .op_i ( aes_op_q ),
318: .mode_i ( aes_mode_q ),
319: .cipher_op_i ( cipher_op ),
320: .manual_operation_i ( manual_operation_q ),
321: .start_i ( reg2hw.trigger.start.q ),
322: .key_clear_i ( reg2hw.trigger.key_clear.q ),
323: .iv_clear_i ( reg2hw.trigger.iv_clear.q ),
324: .data_in_clear_i ( reg2hw.trigger.data_in_clear.q ),
325: .data_out_clear_i ( reg2hw.trigger.data_out_clear.q ),
326: .prng_reseed_i ( reg2hw.trigger.prng_reseed.q ),
327:
328: .key_init_qe_i ( key_init_qe ),
329: .iv_qe_i ( iv_qe ),
330: .data_in_qe_i ( data_in_qe ),
331: .data_out_re_i ( data_out_re ),
332: .data_in_we_o ( data_in_we ),
333: .data_out_we_o ( data_out_we ),
334:
335: .data_in_prev_sel_o ( data_in_prev_sel ),
336: .data_in_prev_we_o ( data_in_prev_we ),
337:
338: .state_in_sel_o ( state_in_sel ),
339: .add_state_in_sel_o ( add_state_in_sel ),
340: .add_state_out_sel_o ( add_state_out_sel ),
341:
342: .ctr_incr_o ( ctr_incr ),
343: .ctr_ready_i ( ctr_ready ),
344: .ctr_we_i ( ctr_we ),
345:
346: .cipher_in_valid_o ( cipher_in_valid ),
347: .cipher_in_ready_i ( cipher_in_ready ),
348: .cipher_out_valid_i ( cipher_out_valid ),
349: .cipher_out_ready_o ( cipher_out_ready ),
350: .cipher_crypt_o ( cipher_crypt ),
351: .cipher_crypt_i ( cipher_crypt_busy ),
352: .cipher_dec_key_gen_o ( cipher_dec_key_gen ),
353: .cipher_dec_key_gen_i ( cipher_dec_key_gen_busy ),
354: .cipher_key_clear_o ( cipher_key_clear ),
355: .cipher_key_clear_i ( cipher_key_clear_busy ),
356: .cipher_data_out_clear_o ( cipher_data_out_clear ),
357: .cipher_data_out_clear_i ( cipher_data_out_clear_busy ),
358:
359: .key_init_sel_o ( key_init_sel ),
360: .key_init_we_o ( key_init_we ),
361: .iv_sel_o ( iv_sel ),
362: .iv_we_o ( iv_we ),
363:
364: .prng_data_req_o ( prng_data_req_o ),
365: .prng_data_ack_i ( prng_data_ack_i ),
366: .prng_reseed_req_o ( prng_reseed_req_o ),
367: .prng_reseed_ack_i ( prng_reseed_ack_i ),
368:
369: .start_o ( hw2reg.trigger.start.d ),
370: .start_we_o ( hw2reg.trigger.start.de ),
371: .key_clear_o ( hw2reg.trigger.key_clear.d ),
372: .key_clear_we_o ( hw2reg.trigger.key_clear.de ),
373: .iv_clear_o ( hw2reg.trigger.iv_clear.d ),
374: .iv_clear_we_o ( hw2reg.trigger.iv_clear.de ),
375: .data_in_clear_o ( hw2reg.trigger.data_in_clear.d ),
376: .data_in_clear_we_o ( hw2reg.trigger.data_in_clear.de ),
377: .data_out_clear_o ( hw2reg.trigger.data_out_clear.d ),
378: .data_out_clear_we_o ( hw2reg.trigger.data_out_clear.de ),
379: .prng_reseed_o ( hw2reg.trigger.prng_reseed.d ),
380: .prng_reseed_we_o ( hw2reg.trigger.prng_reseed.de ),
381:
382: .output_valid_o ( hw2reg.status.output_valid.d ),
383: .output_valid_we_o ( hw2reg.status.output_valid.de ),
384: .input_ready_o ( hw2reg.status.input_ready.d ),
385: .input_ready_we_o ( hw2reg.status.input_ready.de ),
386: .idle_o ( hw2reg.status.idle.d ),
387: .idle_we_o ( hw2reg.status.idle.de ),
388: .stall_o ( hw2reg.status.stall.d ),
389: .stall_we_o ( hw2reg.status.stall.de )
390: );
391:
392: // Input data register clear
393: always_comb begin : data_in_reg_clear
394: for (int i=0; i<4; i++) begin
395: hw2reg.data_in[i].d = '0;
396: hw2reg.data_in[i].de = data_in_we;
397: end
398: end
399:
400: // Control register
401: assign ctrl_we = ctrl_qe & hw2reg.status.idle.d;
402:
403: always_ff @(posedge clk_i or negedge rst_ni) begin : ctrl_reg
404: if (!rst_ni) begin
405: aes_op_q <= AES_ENC;
406: aes_mode_q <= AES_ECB;
407: key_len_q <= AES_128;
408: manual_operation_q <= '0;
409: end else if (ctrl_we) begin
410: aes_op_q <= aes_op_d;
411: aes_mode_q <= aes_mode_d;
412: key_len_q <= key_len_d;
413: manual_operation_q <= reg2hw.ctrl.manual_operation.q;
414: end
415: end
416:
417: /////////////
418: // Outputs //
419: /////////////
420:
421: always_ff @(posedge clk_i) begin : data_out_reg
422: if (data_out_we) begin
423: data_out_q <= data_out_d;
424: end
425: end
426:
427: always_comb begin : key_reg_put
428: for (int i=0; i<8; i++) begin
429: hw2reg.key[i].d = key_init_q[i];
430: end
431: end
432:
433: always_comb begin : iv_reg_put
434: for (int i=0; i<4; i++) begin
435: hw2reg.iv[i].d = {iv_q[2*i+1], iv_q[2*i]};
436: end
437: end
438:
439: always_comb begin : data_out_put
440: for (int i=0; i<4; i++) begin
441: hw2reg.data_out[i].d = data_out_q[i];
442: end
443: end
444:
445: assign hw2reg.ctrl.mode.d = {aes_mode_q};
446: assign hw2reg.ctrl.key_len.d = {key_len_q};
447:
448: // These fields are actually hro. But software must be able observe the current value (rw).
449: assign hw2reg.ctrl.operation.d = {aes_op_q};
450: assign hw2reg.ctrl.manual_operation.d = manual_operation_q;
451:
452: ////////////////
453: // Assertions //
454: ////////////////
455:
456: // Selectors must be known/valid
457: `ASSERT_KNOWN(AesKeyInitSelKnown, key_init_sel)
458: `ASSERT(AesIvSelValid, iv_sel inside {
459: IV_INPUT,
460: IV_DATA_OUT,
461: IV_DATA_IN_PREV,
462: IV_CTR,
463: IV_CLEAR
464: })
465: `ASSERT_KNOWN(AesDataInPrevSelKnown, data_in_prev_sel)
466: `ASSERT(AesModeValid, aes_mode_q inside {
467: AES_ECB,
468: AES_CBC,
469: AES_CTR
470: })
471: `ASSERT_KNOWN(AesOpKnown, aes_op_q)
472: `ASSERT_KNOWN(AesStateInSelKnown, state_in_sel)
473: `ASSERT_KNOWN(AesAddStateInSelKnown, add_state_in_sel)
474: `ASSERT(AesAddStateOutSelValid, add_state_out_sel inside {
475: ADD_SO_ZERO,
476: ADD_SO_IV,
477: ADD_SO_DIP
478: })
479:
480: endmodule
481: