Entity: aes_cipher_core

Diagram

bit AES192Enable bit Masking sbox_impl_e SBoxImpl bit SecAllowForcingMasks bit SecSkipPRNGReseeding int unsigned EntropyWidth int NumShares masking_lfsr_seed_t RndCnstMaskingLfsrSeed mskg_chunk_lfsr_perm_t RndCnstMskgChunkLfsrPerm clk_i rst_ni sp2v_e in_valid_i sp2v_e out_ready_i cfg_valid_i ciph_op_e op_i key_len_e key_len_i sp2v_e crypt_i sp2v_e dec_key_gen_i key_clear_i data_out_clear_i [WidthPRDClearing-1:0] prd_clearing_i force_zero_masks_i entropy_ack_i [EntropyWidth-1:0] entropy_i [3:0] state_init_i [7:0] key_init_i sp2v_e in_ready_o sp2v_e out_valid_o sp2v_e crypt_o sp2v_e dec_key_gen_o key_clear_o data_out_clear_o alert_o [3:0] data_in_mask_o entropy_req_o [3:0] state_o

Description

Copyright lowRISC contributors. Licensed under the Apache License, Version 2.0, see LICENSE for details. SPDX-License-Identifier: Apache-2.0

AES cipher core implementation

This module contains the AES cipher core including, state register, full key and decryption key registers as well as key expand module and control unit.

Masking

If the parameter "Masking" is set to one, first-order masking is applied to the entire cipher core including key expand module. For details, see Rivain et al., "Provably secure higher-order masking of AES" available at https://eprint.iacr.org/2010/441.pdf .

Details on the data formats

This implementation uses 4-dimensional SystemVerilog arrays to represent the AES state:

logic [3:0][3:0][7:0] state_q [NumShares];

The fourth dimension (unpacked) corresponds to the different shares. The first element holds the (masked) data share whereas the other elements hold the masks (masked implementation only). The three packed dimensions correspond to the 128-bit state matrix per share. This implementation uses the same encoding as the Advanced Encryption Standard (AES) FIPS Publication 197 available at https://www.nist.gov/publications/advanced-encryption-standard-aes (see Section 3.4). An input sequence of 16 bytes (128-bit, left most byte is the first one)

b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15

is mapped to the state matrix as

[ b0 b4 b8 b12 ] [ b1 b5 b9 b13 ] [ b2 b6 b10 b14 ] [ b3 b7 b11 b15 ] .

This is mapped to three packed dimensions of SystemVerilog array as follows:

  • The first dimension corresponds to the rows. Thus, state_q[0] gives

    • The first row of the state matrix [ b0 b4 b8 b12 ], or
    • A 32-bit packed SystemVerilog array 32h'{ b12, b8, b4, b0 }.
  • The second dimension corresponds to the columns. To access complete columns, the state matrix must be transposed first. Thus state_transposed = aes_pkg::aes_transpose(state_q) and then state_transposed[1] gives

    • The second column of the state matrix [ b4 b5 b6 b7 ], or
    • A 32-bit packed SystemVerilog array 32h'{ b7, b6, b5, b4 }.
  • The third dimension corresponds to the bytes.

Note that the CSRs are little-endian. The input sequence above is provided to 32-bit DATA_IN_0 - DATA_IN_3 registers as MSB LSB

  • DATA_IN_0 32h'{ b3 , b2 , b1 , b0 }
  • DATA_IN_1 32h'{ b7 , b6 , b4 , b4 }
  • DATA_IN_2 32h'{ b11, b10, b9 , b8 }
  • DATA_IN_3 32h'{ b15, b14, b13, b12 } .

The input state can thus be obtained by transposing the content of the DATA_IN_0 - DATA_IN_3 registers.

Similarly, the implementation uses a 3-dimensional array to represent the AES keys:

logic [7:0][31:0] key_full_q [NumShares]

The third dimension (unpacked) corresponds to the different shares. The first element holds the (masked) key share whereas the other elements hold the masks (masked implementation only). The two packed dimensions correspond to the 256-bit key per share. This implementation uses the same encoding as the Advanced Encryption Standard (AES) FIPS Publication 197 available at https://www.nist.gov/publications/advanced-encryption-standard-aes .

The first packed dimension corresponds to the 8 key words. The second packed dimension corresponds to the 32 bits per key word. A key sequence of 32 bytes (256-bit, left most byte is the first one)

b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 … … b28 b29 b30 b31

is mapped to the key words and registers (little-endian) as MSB LSB

  • KEY_SHARE0_0 32h'{ b3 , b2 , b1 , b0 }
  • KEY_SHARE0_1 32h'{ b7 , b6 , b4 , b4 }
  • KEY_SHARE0_2 32h'{ b11, b10, b9 , b8 }
  • KEY_SHARE0_3 32h'{ b15, b14, b13, b12 }
  • KEY_SHARE0_4 32h'{ . . . . }
  • KEY_SHARE0_5 32h'{ . . . . }
  • KEY_SHARE0_6 32h'{ . . . . }
  • KEY_SHARE0_7 32h'{ b31, b30, b29, b28 } .

Generics

Generic name Type Value Description
AES192Enable bit 1
Masking bit 1
SBoxImpl sbox_impl_e SBoxImplDom
SecAllowForcingMasks bit 0
SecSkipPRNGReseeding bit 0
EntropyWidth int unsigned edn_pkg::ENDPOINT_BUS_WIDTH
NumShares int Masking ? 2 : 1 derived parameter
RndCnstMaskingLfsrSeed masking_lfsr_seed_t RndCnstMaskingLfsrSeedDefault
RndCnstMskgChunkLfsrPerm mskg_chunk_lfsr_perm_t RndCnstMskgChunkLfsrPermDefault

Ports

Port name Direction Type Description
clk_i input
rst_ni input
in_valid_i input sp2v_e Input handshake signals
in_ready_o output sp2v_e
out_valid_o output sp2v_e Output handshake signals
out_ready_i input sp2v_e
cfg_valid_i input Used for gating assertions only.
op_i input ciph_op_e
key_len_i input key_len_e
crypt_i input sp2v_e
crypt_o output sp2v_e
dec_key_gen_i input sp2v_e
dec_key_gen_o output sp2v_e
key_clear_i input
key_clear_o output
data_out_clear_i input Re-use the cipher core muxes.
data_out_clear_o output
alert_o output
prd_clearing_i input [WidthPRDClearing-1:0] Pseudo-random data for register clearing
force_zero_masks_i input Useful for SCA only.
data_in_mask_o output [3:0]
entropy_req_o output
entropy_ack_i input
entropy_i input [EntropyWidth-1:0]
state_init_i input [3:0] I/O data & initial key
key_init_i input [7:0]
state_o output [3:0]

Signals

Name Type Description
state_d logic [3:0][3:0][7:0] Signals
state_q logic [3:0][3:0][7:0]
state_we_ctrl sp2v_e
state_we sp2v_e
state_sel_raw logic [StateSelWidth-1:0]
state_sel_ctrl state_sel_e
state_sel state_sel_e
state_sel_err logic
sub_bytes_en sp2v_e
sub_bytes_out_req sp2v_e
sub_bytes_out_ack sp2v_e
sub_bytes_err logic
sub_bytes_out logic [3:0][3:0][7:0]
sb_in_mask logic [3:0][3:0][7:0]
sb_out_mask logic [3:0][3:0][7:0]
shift_rows_in logic [3:0][3:0][7:0]
shift_rows_out logic [3:0][3:0][7:0]
mix_columns_out logic [3:0][3:0][7:0]
add_round_key_in logic [3:0][3:0][7:0]
add_round_key_out logic [3:0][3:0][7:0]
add_rk_sel_raw logic [AddRKSelWidth-1:0]
add_rk_sel_ctrl add_rk_sel_e
add_rk_sel add_rk_sel_e
add_rk_sel_err logic
key_full_d logic [7:0][31:0]
key_full_q logic [7:0][31:0]
key_full_we_ctrl sp2v_e
key_full_we sp2v_e
key_full_sel_raw logic [KeyFullSelWidth-1:0]
key_full_sel_ctrl key_full_sel_e
key_full_sel key_full_sel_e
key_full_sel_err logic
key_dec_d logic [7:0][31:0]
key_dec_q logic [7:0][31:0]
key_dec_we_ctrl sp2v_e
key_dec_we sp2v_e
key_dec_sel_raw logic [KeyDecSelWidth-1:0]
key_dec_sel_ctrl key_dec_sel_e
key_dec_sel key_dec_sel_e
key_dec_sel_err logic
key_expand_out logic [7:0][31:0]
key_expand_op ciph_op_e
key_expand_en sp2v_e
key_expand_out_req sp2v_e
key_expand_out_ack sp2v_e
key_expand_err logic
key_expand_clear logic
key_expand_round logic [3:0]
key_words_sel_raw logic [KeyWordsSelWidth-1:0]
key_words_sel_ctrl key_words_sel_e
key_words_sel key_words_sel_e
key_words_sel_err logic
key_words logic [3:0][31:0]
key_bytes logic [3:0][3:0][7:0]
key_mix_columns_out logic [3:0][3:0][7:0]
round_key logic [3:0][3:0][7:0]
round_key_sel_raw logic [RoundKeySelWidth-1:0]
round_key_sel_ctrl round_key_sel_e
round_key_sel round_key_sel_e
round_key_sel_err logic
mux_sel_err logic
sp_enc_err_d logic
sp_enc_err_q logic
prd_clearing_128 logic [127:0] Pseudo-random data for clearing and masking purposes
prd_clearing_256 logic [255:0]
prd_masking logic [WidthPRDMasking-1:0]
prd_sub_bytes logic [3:0][3:0][WidthPRDSBox-1:0]
prd_key_expand logic [WidthPRDKey-1:0]
prd_masking_upd logic
prd_masking_rsd_req logic
prd_masking_rsd_ack logic
sp2v_sig sp2v_e [NumSp2VSig-1:0]
sp2v_sig_chk sp2v_e [NumSp2VSig-1:0]
sp2v_sig_chk_raw logic [NumSp2VSig-1:0][Sp2VWidth-1:0]
sp2v_sig_err logic [NumSp2VSig-1:0]

Constants

Name Type Value Description
NumShares int Masking ? 2 : 1 derived parameter
WidthPRDRow int unsigned 4*WidthPRDSBox Extract randomness for masking the input data.
The masking PRNG is used for generating both the PRD for the S-Boxes/SubBytes operation as well as for the input data masks. When using any of the masked Canright S-Box implementations, it is important that the SubBytes input masks (generated by the PRNG in Round X-1) and the SubBytes output masks (generated by the PRNG in Round X) are independent. Inside the PRNG, this is achieved by using multiple, separately re-seeded LFSR chunks and by selecting the separate LFSR chunks in alternating fashion. Since the input data masks become the SubBytes input masks in the first round, we select the same 8 bit lanes for the input data masks which are also used to form the SubBytes output mask for the masked Canright S-Box implementations, i.e., the 8 LSBs of the per S-Box PRD. In particular, we have:
prd_masking = { prd_key_expand, … , sb_prd[4], sb_out_mask[4], sb_prd[0], sb_out_mask[0] }
Where sb_out_mask[x] contains the SubBytes output mask for byte x (when using a masked Canright S-Box implementation) and sb_prd[x] contains additional PRD consumed by SubBytes for byte x.
When using a masked S-Box implementation other than Canright, we still select the 8 LSBs of the per-S-Box PRD to form the input data mask of the corresponding byte. We do this to distribute the input data masks over all LFSR chunks of the masking PRNG. We do the extraction on a row basis.
NumSp2VSig int unsigned 3 //////////////////////////// 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. We use vectors of sparsely encoded signals to reduce code duplication.

Processes

Type: always_comb

Description
//////// Data // //////// State registers

Type: always_ff

Type: always_comb

Type: always_comb

Description
/////// Key // /////// Full Key registers

Type: always_ff

Type: always_comb

Description
Decryption Key registers

Type: always_ff

Type: always_comb

Type: always_ff

Description
We need to register the collected error signal to avoid circular loops in the cipher core controller related to out_valid_o and detecting errors in state_we_o and sub_bytes_out_ack.

Instantiations

Description
Cipher data path

Description
Key expand data path

Description
///////////
Control //
///////////
Control

Description
/////////////
Selectors //
/////////////
We use sparse encodings for these mux selector signals and must ensure that:

  1. The synthesis tool doesn't optimize away the sparse encoding.

  2. The selector signal is always valid. More precisely, an alert or SVA is triggered if a
    selector signal takes on an invalid value.

  3. The alert signal remains asserted until reset even if the selector signal becomes valid
    again. This is achieved by driving the control FSM into the terminal error state whenever
    any mux selector signal becomes invalid.

    If any mux selector signal becomes invalid, the cipher core further immediately de-asserts
    the out_valid_o signal to prevent any data from being released.