blob: 3e0663a7431c3c8758ae8dd4626e745fcd6dafcc [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// AES cipher core control
//
// This module controls the AES cipher core including the key expand module.
`include "prim_assert.sv"
module aes_cipher_control import aes_pkg::*;
#(
parameter bit Masking = 0,
parameter sbox_impl_e SBoxImpl = SBoxImplLut
) (
input logic clk_i,
input logic rst_ni,
// Input handshake signals
input sp2v_e in_valid_i,
output sp2v_e in_ready_o,
// Output handshake signals
output sp2v_e out_valid_o,
input sp2v_e out_ready_i,
// Control and sync signals
input logic cfg_valid_i,
input ciph_op_e op_i,
input key_len_e key_len_i,
input sp2v_e crypt_i,
output sp2v_e crypt_o,
input sp2v_e dec_key_gen_i,
output sp2v_e dec_key_gen_o,
input logic key_clear_i,
output logic key_clear_o,
input logic data_out_clear_i,
output logic data_out_clear_o,
input logic mux_sel_err_i,
input logic sp_enc_err_i,
output logic alert_o,
// Control signals for masking PRNG
output logic prng_update_o,
output logic prng_reseed_req_o,
input logic prng_reseed_ack_i,
// Control and sync signals for cipher data path
output state_sel_e state_sel_o,
output sp2v_e state_we_o,
output sp2v_e sub_bytes_en_o,
input sp2v_e sub_bytes_out_req_i,
output sp2v_e sub_bytes_out_ack_o,
output add_rk_sel_e add_rk_sel_o,
// Control and sync signals for key expand data path
output ciph_op_e key_expand_op_o,
output key_full_sel_e key_full_sel_o,
output sp2v_e key_full_we_o,
output key_dec_sel_e key_dec_sel_o,
output sp2v_e key_dec_we_o,
output sp2v_e key_expand_en_o,
input sp2v_e key_expand_out_req_i,
output sp2v_e key_expand_out_ack_o,
output logic key_expand_clear_o,
output logic [3:0] key_expand_round_o,
output key_words_sel_e key_words_sel_o,
output round_key_sel_e round_key_sel_o
);
// Types
// $ ./sparse-fsm-encode.py -d 3 -m 7 -n 6 \
// -s 31468618 --language=sv
//
// Hamming distance histogram:
//
// 0: --
// 1: --
// 2: --
// 3: |||||||||||||||||||| (57.14%)
// 4: ||||||||||||||| (42.86%)
// 5: --
// 6: --
//
// Minimum Hamming distance: 3
// Maximum Hamming distance: 4
//
localparam int StateWidth = 6;
typedef enum logic [StateWidth-1:0] {
IDLE = 6'b111100,
INIT = 6'b101001,
ROUND = 6'b010000,
FINISH = 6'b100010,
CLEAR_S = 6'b011011,
CLEAR_KD = 6'b110111,
ERROR = 6'b001110
} aes_cipher_ctrl_e;
aes_cipher_ctrl_e aes_cipher_ctrl_ns, aes_cipher_ctrl_cs;
// Signals
logic [3:0] rnd_ctr_d, rnd_ctr_q;
logic [3:0] rnd_ctr_rem_d, rnd_ctr_rem_q;
logic [3:0] rnd_ctr_sum;
logic [3:0] num_rounds_d, num_rounds_q;
logic [3:0] num_rounds_regular;
logic rnd_ctr_parity, rnd_ctr_parity_d, rnd_ctr_parity_q;
logic rnd_ctr_err, rnd_ctr_err_sum, rnd_ctr_err_parity;
sp2v_e crypt_d, crypt_q;
sp2v_e dec_key_gen_d, dec_key_gen_q;
logic key_clear_d, key_clear_q;
logic data_out_clear_d, data_out_clear_q;
logic prng_reseed_done_d, prng_reseed_done_q;
sp2v_e sub_bytes_out_req;
sp2v_e key_expand_out_req;
sp2v_e advance, advance_chk;
sp2v_e in_valid;
sp2v_e out_ready;
sp2v_e crypt;
sp2v_e dec_key_gen;
logic sp_enc_err;
// cfg_valid_i is used for gating assertions only.
logic unused_cfg_valid;
assign unused_cfg_valid = cfg_valid_i;
// FSM
always_comb begin : aes_cipher_ctrl_fsm
// Handshake signals
in_ready_o = SP2V_LOW;
out_valid_o = SP2V_LOW;
// Masking PRNG signals
prng_update_o = 1'b0;
prng_reseed_req_o = 1'b0;
// Cipher data path
state_sel_o = STATE_ROUND;
state_we_o = SP2V_LOW;
add_rk_sel_o = ADD_RK_ROUND;
sub_bytes_en_o = SP2V_LOW;
sub_bytes_out_ack_o = SP2V_LOW;
// Key expand data path
key_full_sel_o = KEY_FULL_ROUND;
key_full_we_o = SP2V_LOW;
key_dec_sel_o = KEY_DEC_EXPAND;
key_dec_we_o = SP2V_LOW;
key_expand_en_o = SP2V_LOW;
key_expand_out_ack_o = SP2V_LOW;
key_expand_clear_o = 1'b0;
key_words_sel_o = KEY_WORDS_ZERO;
round_key_sel_o = ROUND_KEY_DIRECT;
// FSM
aes_cipher_ctrl_ns = aes_cipher_ctrl_cs;
num_rounds_d = num_rounds_q;
rnd_ctr_d = rnd_ctr_q;
rnd_ctr_rem_d = rnd_ctr_rem_q;
crypt_d = crypt_q;
dec_key_gen_d = dec_key_gen_q;
key_clear_d = key_clear_q;
data_out_clear_d = data_out_clear_q;
prng_reseed_done_d = prng_reseed_done_q | prng_reseed_ack_i;
advance = SP2V_LOW;
// Alert
alert_o = 1'b0;
unique case (aes_cipher_ctrl_cs)
IDLE: begin
dec_key_gen_d = SP2V_LOW;
// Signal that we are ready, wait for handshake.
in_ready_o = SP2V_HIGH;
if (in_valid == SP2V_HIGH) begin
if (key_clear_i || data_out_clear_i) begin
// Clear internal key registers. The cipher core muxes are used to clear the data
// output registers.
key_clear_d = key_clear_i;
data_out_clear_d = data_out_clear_i;
// To clear the data output registers, we must first clear the state.
aes_cipher_ctrl_ns = data_out_clear_i ? CLEAR_S : CLEAR_KD;
end else if (dec_key_gen == SP2V_HIGH || crypt == SP2V_HIGH) begin
// Start encryption/decryption or generation of start key for decryption.
crypt_d = (dec_key_gen_i == SP2V_LOW) ? crypt : SP2V_LOW;
dec_key_gen_d = dec_key_gen_i;
// Load input data to state
state_sel_o = (dec_key_gen_i == SP2V_HIGH) ? STATE_CLEAR : STATE_INIT;
state_we_o = SP2V_HIGH;
// Make the masking PRNG advance. The current pseudo-random data is used to mask the
// input data.
prng_update_o = (dec_key_gen_i == SP2V_HIGH) ? 1'b0 : Masking;
// Init key expand
key_expand_clear_o = 1'b1;
// Load full key
key_full_sel_o = (dec_key_gen_i == SP2V_HIGH) ? KEY_FULL_ENC_INIT :
(op_i == CIPH_FWD) ? KEY_FULL_ENC_INIT :
KEY_FULL_DEC_INIT;
key_full_we_o = SP2V_HIGH;
// Load num_rounds, initialize round counters.
num_rounds_d = (key_len_i == AES_128) ? 4'd10 :
(key_len_i == AES_192) ? 4'd12 :
4'd14;
rnd_ctr_rem_d = num_rounds_d;
rnd_ctr_d = '0;
aes_cipher_ctrl_ns = INIT;
end else begin
// Handshake without a valid command. We should never get here. If we do (e.g. via a
// malicious glitch), error out immediately.
aes_cipher_ctrl_ns = ERROR;
end
end
end
INIT: begin
// Initial round: just add key to state
add_rk_sel_o = ADD_RK_INIT;
// Select key words for initial add_round_key
key_words_sel_o = (dec_key_gen_q == SP2V_HIGH) ? KEY_WORDS_ZERO :
(key_len_i == AES_128) ? KEY_WORDS_0123 :
(key_len_i == AES_192 && op_i == CIPH_FWD) ? KEY_WORDS_0123 :
(key_len_i == AES_192 && op_i == CIPH_INV) ? KEY_WORDS_2345 :
(key_len_i == AES_256 && op_i == CIPH_FWD) ? KEY_WORDS_0123 :
(key_len_i == AES_256 && op_i == CIPH_INV) ? KEY_WORDS_4567 : KEY_WORDS_ZERO;
// Clear masking PRNG reseed status.
prng_reseed_done_d = 1'b0;
// AES-256 has two round keys available right from beginning. Pseudo-random data is
// required by KeyExpand only.
if (key_len_i != AES_256) begin
// Advance in sync with KeyExpand. Based on the S-Box implementation, it can take
// multiple cycles to finish. Wait for handshake. The DOM S-Boxes take fresh PRD
// in every cycle except the last.
advance = key_expand_out_req;
prng_update_o = (SBoxImpl == SBoxImplDom) ? (advance_chk == SP2V_LOW) : Masking;
key_expand_en_o = SP2V_HIGH;
if (advance_chk == SP2V_HIGH) begin
key_expand_out_ack_o = SP2V_HIGH;
state_we_o = (dec_key_gen_q == SP2V_LOW) ? SP2V_HIGH : SP2V_LOW;
key_full_we_o = SP2V_HIGH;
rnd_ctr_d = rnd_ctr_q + 4'b0001;
rnd_ctr_rem_d = rnd_ctr_rem_q - 4'b0001;
aes_cipher_ctrl_ns = ROUND;
end
end else begin
state_we_o = (dec_key_gen_q == SP2V_LOW) ? SP2V_HIGH : SP2V_LOW;
rnd_ctr_d = rnd_ctr_q + 4'b0001;
rnd_ctr_rem_d = rnd_ctr_rem_q - 4'b0001;
aes_cipher_ctrl_ns = ROUND;
end
end
ROUND: begin
// Normal rounds
// Select key words for add_round_key
key_words_sel_o = (dec_key_gen_q == SP2V_HIGH) ? KEY_WORDS_ZERO :
(key_len_i == AES_128) ? KEY_WORDS_0123 :
(key_len_i == AES_192 && op_i == CIPH_FWD) ? KEY_WORDS_2345 :
(key_len_i == AES_192 && op_i == CIPH_INV) ? KEY_WORDS_0123 :
(key_len_i == AES_256 && op_i == CIPH_FWD) ? KEY_WORDS_4567 :
(key_len_i == AES_256 && op_i == CIPH_INV) ? KEY_WORDS_0123 : KEY_WORDS_ZERO;
// Keep requesting PRNG reseeding until it is acknowledged.
prng_reseed_req_o = Masking & ~prng_reseed_done_q;
// Select round key: direct or mixed (equivalent inverse cipher)
round_key_sel_o = (op_i == CIPH_FWD) ? ROUND_KEY_DIRECT : ROUND_KEY_MIXED;
// Advance in sync with SubBytes and KeyExpand. Based on the S-Box implementation, both can
// take multiple cycles to finish. Wait for handshake. Make the masking PRNG advance every
// cycle. The DOM S-Boxes take fresh PRD in every cycle except the last.
advance = ((dec_key_gen_q == SP2V_HIGH || sub_bytes_out_req == SP2V_HIGH) &&
key_expand_out_req == SP2V_HIGH) ? SP2V_HIGH : SP2V_LOW;
prng_update_o = (SBoxImpl == SBoxImplDom) ? (advance_chk == SP2V_LOW) : Masking;
sub_bytes_en_o = (dec_key_gen_q == SP2V_LOW) ? SP2V_HIGH : SP2V_LOW;
key_expand_en_o = SP2V_HIGH;
if (advance_chk == SP2V_HIGH) begin
sub_bytes_out_ack_o = (dec_key_gen_q == SP2V_LOW) ? SP2V_HIGH : SP2V_LOW;
key_expand_out_ack_o = SP2V_HIGH;
state_we_o = (dec_key_gen_q == SP2V_LOW) ? SP2V_HIGH : SP2V_LOW;
key_full_we_o = SP2V_HIGH;
// Update round
rnd_ctr_d = rnd_ctr_q + 4'b0001;
rnd_ctr_rem_d = rnd_ctr_rem_q - 4'b0001;
// Are we doing the last regular round?
if (rnd_ctr_q == num_rounds_regular) begin
aes_cipher_ctrl_ns = FINISH;
if (dec_key_gen_q == SP2V_HIGH) begin
// Write decryption key.
key_dec_we_o = SP2V_HIGH;
// Indicate that we are done, try to perform the handshake. But we don't wait here.
// If we don't get the handshake now, we will wait in the finish state. When using
// masking, we only finish if the masking PRNG has been reseeded.
out_valid_o = Masking ? (prng_reseed_done_q ? SP2V_HIGH : SP2V_LOW) : SP2V_HIGH;
if (out_valid_o == SP2V_HIGH && out_ready == SP2V_HIGH) begin
// Go to idle state directly.
dec_key_gen_d = SP2V_LOW;
aes_cipher_ctrl_ns = IDLE;
end
end
end // rnd_ctr_q
end // SubBytes/KeyExpand REQ/ACK
end
FINISH: begin
// Final round
// Select key words for add_round_key
key_words_sel_o = (dec_key_gen_q == SP2V_HIGH) ? KEY_WORDS_ZERO :
(key_len_i == AES_128) ? KEY_WORDS_0123 :
(key_len_i == AES_192 && op_i == CIPH_FWD) ? KEY_WORDS_2345 :
(key_len_i == AES_192 && op_i == CIPH_INV) ? KEY_WORDS_0123 :
(key_len_i == AES_256 && op_i == CIPH_FWD) ? KEY_WORDS_4567 :
(key_len_i == AES_256 && op_i == CIPH_INV) ? KEY_WORDS_0123 : KEY_WORDS_ZERO;
// Skip mix_columns
add_rk_sel_o = ADD_RK_FINAL;
// Keep requesting PRNG reseeding until it is acknowledged.
prng_reseed_req_o = Masking & ~prng_reseed_done_q;
// Once we're done, we won't need the state anymore. We actually clear it when progressing
// to the next state.
state_sel_o = STATE_CLEAR;
// Advance in sync with SubBytes. Based on the S-Box implementation, it can take multiple
// cycles to finish. Only indicate that we are done if:
// - we have valid output (SubBytes finished),
// - the masking PRNG has been reseeded (if masking is used),
// - all mux selector signals are valid (don't release data in case of errors), and
// - all sparsely encoded signals are valid (don't release data in case of errors).
// Perform both handshakes simultaneously.
advance = (sub_bytes_out_req == SP2V_HIGH ||
dec_key_gen_q == SP2V_HIGH) ? SP2V_HIGH : SP2V_LOW;
sub_bytes_en_o = (dec_key_gen_q == SP2V_LOW) ? SP2V_HIGH : SP2V_LOW;
out_valid_o = (advance_chk == SP2V_HIGH &&
Masking == prng_reseed_done_q &&
!mux_sel_err_i && !sp_enc_err) ? SP2V_HIGH : SP2V_LOW;
// When using DOM S-Boxes, make the masking PRNG advance every cycle until the output is
// ready. For other S-Boxes, make it advance once only. Updating it while being stalled
// would cause non-DOM S-Boxes to be re-evaluated, thereby creating additional SCA leakage.
prng_update_o = (SBoxImpl == SBoxImplDom) ? (advance_chk == SP2V_LOW) :
Masking ? (out_valid_o == SP2V_HIGH && out_ready == SP2V_HIGH) : 1'b0;
if (out_valid_o == SP2V_HIGH && out_ready == SP2V_HIGH) begin
sub_bytes_out_ack_o = (dec_key_gen_q == SP2V_LOW) ? SP2V_HIGH : SP2V_LOW;
// Clear the state.
state_we_o = SP2V_HIGH;
crypt_d = SP2V_LOW;
// If we were generating the decryption key and didn't get the handshake in the last
// regular round, we should clear dec_key_gen now.
dec_key_gen_d = SP2V_LOW;
aes_cipher_ctrl_ns = IDLE;
end
end
CLEAR_S: begin
// Clear the state with pseudo-random data.
state_we_o = SP2V_HIGH;
state_sel_o = STATE_CLEAR;
aes_cipher_ctrl_ns = CLEAR_KD;
end
CLEAR_KD: begin
// Clear internal key registers and/or external data output registers.
if (key_clear_q) begin
key_full_sel_o = KEY_FULL_CLEAR;
key_full_we_o = SP2V_HIGH;
key_dec_sel_o = KEY_DEC_CLEAR;
key_dec_we_o = SP2V_HIGH;
end
if (data_out_clear_q) begin
// Forward the state (previously cleared with psuedo-random data).
add_rk_sel_o = ADD_RK_INIT;
key_words_sel_o = KEY_WORDS_ZERO;
round_key_sel_o = ROUND_KEY_DIRECT;
end
// Indicate that we are done, wait for handshake.
out_valid_o = SP2V_HIGH;
if (out_ready == SP2V_HIGH) begin
key_clear_d = 1'b0;
data_out_clear_d = 1'b0;
aes_cipher_ctrl_ns = IDLE;
end
end
ERROR: begin
// Terminal error state
alert_o = 1'b1;
end
// We should never get here. If we do (e.g. via a malicious glitch), error out immediately.
default: begin
aes_cipher_ctrl_ns = ERROR;
end
endcase
// Unconditionally jump into the terminal error state in case a mux selector or a sparsely
// encoded signal becomes invalid, or in case we have detected a fault in the round counter.
if (mux_sel_err_i || sp_enc_err || rnd_ctr_err) begin
aes_cipher_ctrl_ns = ERROR;
end
end
// This primitive is used to place a size-only constraint on the
// flops in order to prevent FSM state encoding optimizations.
logic [StateWidth-1:0] aes_cipher_ctrl_cs_raw;
assign aes_cipher_ctrl_cs = aes_cipher_ctrl_e'(aes_cipher_ctrl_cs_raw);
prim_flop #(
.Width(StateWidth),
.ResetValue(StateWidth'(IDLE))
) u_state_regs (
.clk_i,
.rst_ni,
.d_i ( aes_cipher_ctrl_ns ),
.q_o ( aes_cipher_ctrl_cs_raw )
);
always_ff @(posedge clk_i or negedge rst_ni) begin : reg_fsm
if (!rst_ni) begin
num_rounds_q <= '0;
key_clear_q <= 1'b0;
data_out_clear_q <= 1'b0;
prng_reseed_done_q <= 1'b0;
end else begin
num_rounds_q <= num_rounds_d;
key_clear_q <= key_clear_d;
data_out_clear_q <= data_out_clear_d;
prng_reseed_done_q <= prng_reseed_done_d;
end
end
// Use separate signal for number of regular rounds.
assign num_rounds_regular = num_rounds_q - 4'd1;
// Use separate signal for key expand operation, forward round.
assign key_expand_op_o = (dec_key_gen_d == SP2V_HIGH ||
dec_key_gen_q == SP2V_HIGH) ? CIPH_FWD : op_i;
assign key_expand_round_o = rnd_ctr_q;
// Let the main controller know whate we are doing.
assign crypt_o = crypt_q;
assign dec_key_gen_o = dec_key_gen_q;
assign key_clear_o = key_clear_q;
assign data_out_clear_o = data_out_clear_q;
//////////////////////////////
// Round Counter Protection //
//////////////////////////////
// To protect the round counter against fault injection, we use two counters:
// - rnd_ctr_d/q counts the executed rounds. It is initialized to 0 and counts up.
// - rnd_ctr_rem_d/q counts the remaining rounds. It is initialized to num_rounds_q and counts
// down.
// In addition, we use one parity bit for the rnd_ctr_d/q counter.
//
// An alert is signaled and the FSM goes into the terminal error state if
// i) the sum of the counters doesn't add up, i.e. rnd_ctr_q + rnd_ctr_rem_q != num_rounds_q, or
// ii) the parity information is incorrect.
// The following primitives are used to place size-only constraints on the
// flops in order to prevent optimizations on the protected round counter.
prim_flop #(
.Width(4),
.ResetValue('0)
) u_rnd_ctr_regs (
.clk_i,
.rst_ni,
.d_i ( rnd_ctr_d ),
.q_o ( rnd_ctr_q )
);
prim_flop #(
.Width(4),
.ResetValue('0)
) u_rnd_ctr_rem_regs (
.clk_i,
.rst_ni,
.d_i ( rnd_ctr_rem_d ),
.q_o ( rnd_ctr_rem_q )
);
prim_flop #(
.Width(1),
.ResetValue('0)
) u_rnd_ctr_par_reg (
.clk_i,
.rst_ni,
.d_i ( rnd_ctr_parity_d ),
.q_o ( rnd_ctr_parity_q )
);
// Generate parity bits and sum.
assign rnd_ctr_parity_d = ^rnd_ctr_d;
assign rnd_ctr_parity = ^rnd_ctr_q;
assign rnd_ctr_sum = rnd_ctr_q + rnd_ctr_rem_q;
// Detect faults.
assign rnd_ctr_err_sum = (rnd_ctr_sum != num_rounds_q) ? 1'b1 : 1'b0;
assign rnd_ctr_err_parity = (rnd_ctr_parity != rnd_ctr_parity_q) ? 1'b1 : 1'b0;
assign rnd_ctr_err = rnd_ctr_err_sum | rnd_ctr_err_parity;
//////////////////////////////
// Sparsely Encoded Signals //
//////////////////////////////
// We use sparse encodings for various critical signals and must ensure that:
// 1. The synthesis tool doesn't optimize away the sparse encoding.
// 2. The sparsely encoded signal is always valid. More precisely, an alert or SVA is triggered
// if a sparse signal takes on an invalid value.
// 3. The alert signal remains asserted until reset even if the sparse signal becomes valid again
// This is achieved by driving the control FSM into the terminal error state whenever any
// sparsely encoded signal becomes invalid.
//
// If any sparsely encoded signal becomes invalid, the cipher core further immediately de-asserts
// the out_valid_o signal to prevent any data from being released.
// The following primitives are used to place a size-only constraint on the
// flops in order to prevent optimizations on these status signals.
logic [Sp2VWidth-1:0] crypt_q_raw;
prim_flop #(
.Width ( Sp2VWidth ),
.ResetValue ( Sp2VWidth'(SP2V_LOW) )
) u_crypt_regs (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.d_i ( crypt_d ),
.q_o ( crypt_q_raw )
);
logic [Sp2VWidth-1:0] dec_key_gen_q_raw;
prim_flop #(
.Width ( Sp2VWidth ),
.ResetValue ( Sp2VWidth'(SP2V_LOW) )
) u_dec_key_gen_regs (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.d_i ( dec_key_gen_d ),
.q_o ( dec_key_gen_q_raw )
);
// We use vectors of sparsely encoded signals to reduce code duplication.
localparam int unsigned NumSp2VSig = 9;
sp2v_e [NumSp2VSig-1:0] sp2v_sig;
sp2v_e [NumSp2VSig-1:0] sp2v_sig_chk;
logic [NumSp2VSig-1:0][Sp2VWidth-1:0] sp2v_sig_chk_raw;
logic [NumSp2VSig-1:0] sp2v_sig_err;
assign sp2v_sig[0] = in_valid_i;
assign sp2v_sig[1] = out_ready_i;
assign sp2v_sig[2] = crypt_i;
assign sp2v_sig[3] = dec_key_gen_i;
assign sp2v_sig[4] = sp2v_e'(crypt_q_raw);
assign sp2v_sig[5] = sp2v_e'(dec_key_gen_q_raw);
assign sp2v_sig[6] = advance;
assign sp2v_sig[7] = sub_bytes_out_req_i;
assign sp2v_sig[8] = key_expand_out_req_i;
// Individually check sparsely encoded signals.
for (genvar i = 0; i < NumSp2VSig; i++) begin : gen_sel_buf_chk
aes_sel_buf_chk #(
.Num ( Sp2VNum ),
.Width ( Sp2VWidth )
) u_aes_sp2v_sig_buf_chk_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.sel_i ( sp2v_sig[i] ),
.sel_o ( sp2v_sig_chk_raw[i] ),
.err_o ( sp2v_sig_err[i] )
);
assign sp2v_sig_chk[i] = sp2v_e'(sp2v_sig_chk_raw[i]);
end
assign in_valid = sp2v_sig_chk[0];
assign out_ready = sp2v_sig_chk[1];
assign crypt = sp2v_sig_chk[2];
assign dec_key_gen = sp2v_sig_chk[3];
assign crypt_q = sp2v_sig_chk[4];
assign dec_key_gen_q = sp2v_sig_chk[5];
assign advance_chk = sp2v_sig_chk[6];
assign sub_bytes_out_req = sp2v_sig_chk[7];
assign key_expand_out_req = sp2v_sig_chk[8];
// Collect encoding errors.
// We instantiate the checker modules as close as possible to where the sparsely encoded signals
// are used. Here, we collect also encoding errors detected in other places of the cipher core.
assign sp_enc_err = |sp2v_sig_err | sp_enc_err_i;
////////////////
// Assertions //
////////////////
// Selectors must be known/valid
`ASSERT_KNOWN(AesCiphOpKnown, op_i)
`ASSERT(AesKeyLenValid, cfg_valid_i |-> key_len_i inside {
AES_128,
AES_192,
AES_256
})
`ASSERT(AesControlStateValid, !alert_o |-> aes_cipher_ctrl_cs inside {
IDLE,
INIT,
ROUND,
FINISH,
CLEAR_S,
CLEAR_KD
})
endmodule