blob: 6eeb549ae882b9cf3ccdd94772ba2f3260c1c6ce [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 package
package aes_pkg;
// If this parameter is set, fatal alerts clear all status and trigger bits to zero. By
// default, it's not set, i.e., no clearing is happening, in order to simplify debugging.
parameter bit ClearStatusOnFatalAlert = 1'b0;
// The initial key is always provided in two shares, independently whether the cipher core is
// masked or not.
parameter int unsigned NumSharesKey = 2;
// Software updates IV in chunks of 32 bits, the counter updates 16 bits at a time.
parameter int unsigned SliceSizeCtr = 16;
parameter int unsigned NumSlicesCtr = aes_reg_pkg::NumRegsIv * 32 / SliceSizeCtr;
parameter int unsigned SliceIdxWidth = prim_util_pkg::vbits(NumSlicesCtr);
// Widths of signals carrying pseudo-random data for clearing
parameter int unsigned WidthPRDClearing = 64;
parameter int unsigned NumChunksPRDClearing128 = 128/WidthPRDClearing;
parameter int unsigned NumChunksPRDClearing256 = 256/WidthPRDClearing;
// Widths of signals carrying pseudo-random data for masking
parameter int unsigned WidthPRDSBox = 8; // Number PRD bits per S-Box. This includes the
// 8 bits for the output mask when using any of the
// masked Canright S-Box implementations.
parameter int unsigned WidthPRDData = 16*WidthPRDSBox; // 16 S-Boxes for the data path
parameter int unsigned WidthPRDKey = 4*WidthPRDSBox; // 4 S-Boxes for the key expand
parameter int unsigned WidthPRDMasking = WidthPRDData + WidthPRDKey;
parameter int unsigned ChunkSizePRDMasking = WidthPRDMasking/5;
// Clearing PRNG default LFSR seed and permutation
// These LFSR parameters have been generated with
// $ util/design/gen-lfsr-seed.py --width 64 --seed 31468618 --prefix "Clearing"
parameter int ClearingLfsrWidth = 64;
typedef logic [ClearingLfsrWidth-1:0] clearing_lfsr_seed_t;
typedef logic [ClearingLfsrWidth-1:0][$clog2(ClearingLfsrWidth)-1:0] clearing_lfsr_perm_t;
parameter clearing_lfsr_seed_t RndCnstClearingLfsrSeedDefault = 64'hc32d580f74f1713a;
parameter clearing_lfsr_perm_t RndCnstClearingLfsrPermDefault = {
128'hb33fdfc81deb6292c21f8a3102585067,
256'h9c2f4be1bbe937b4b7c9d7f4e57568d99c8ae291a899143e0d8459d31b143223
};
// A second permutation is needed for the second share.
parameter clearing_lfsr_perm_t RndCnstClearingSharePermDefault = {
128'hf66fd61b27847edc2286706fb3a2e900,
256'h9736b95ac3f3b5205caf8dc536aad73605d393c8dd94476e830e97891d4828d0
};
// Masking PRNG default LFSR seed and permutation
// We use a single seed that is split down into chunks internally.
// These LFSR parameters have been generated with
// $ util/design/gen-lfsr-seed.py --width 160 --seed 31468618 --prefix "Masking"
parameter int MaskingLfsrWidth = 160; // = WidthPRDMasking = WidthPRDSBox * (16 + 4)
typedef logic [MaskingLfsrWidth-1:0] masking_lfsr_seed_t;
typedef logic [MaskingLfsrWidth-1:0][$clog2(MaskingLfsrWidth)-1:0] masking_lfsr_perm_t;
parameter masking_lfsr_seed_t RndCnstMaskingLfsrSeedDefault =
160'hc132b5723c5a4cf4743b3c7c32d580f74f1713a;
parameter masking_lfsr_perm_t RndCnstMaskingLfsrPermDefault = {
256'h17261943423e4c5c03872194050c7e5f8497081d96666d406f4b606473303469,
256'h8e7c721c8832471f59919e0b128f067b25622768462e554d8970815d490d7f44,
256'h048c867d907a239b20220f6c79071a852d76485452189f14091b1e744e396737,
256'h4f785b772b352f6550613c58130a8b104a3f28019c9a380233956b00563a512c,
256'h808d419d63982a16995e0e3b57826a36718a9329452492533d83115a75316e15
};
typedef enum integer {
SBoxImplLut, // Unmasked LUT-based S-Box
SBoxImplCanright, // Unmasked Canright S-Box, see aes_sbox_canright.sv
SBoxImplCanrightMasked, // First-order masked Canright S-Box
// see aes_sbox_canright_masked.sv
SBoxImplCanrightMaskedNoreuse, // First-order masked Canright S-Box without mask reuse,
// see aes_sbox_canright_masked_noreuse.sv
SBoxImplDom // First-order masked S-Box using domain-oriented masking,
// see aes_sbox_canright_dom.sv
} sbox_impl_e;
// Parameters used for controlgroups in the coverage
parameter int AES_OP_WIDTH = 2;
parameter int AES_MODE_WIDTH = 6;
parameter int AES_KEYLEN_WIDTH = 3;
parameter int AES_PRNGRESEEDRATE_WIDTH = 3;
// SEC_CM: MAIN.CONFIG.SPARSE
typedef enum logic [AES_OP_WIDTH-1:0] {
AES_ENC = 2'b01,
AES_DEC = 2'b10
} aes_op_e;
// SEC_CM: MAIN.CONFIG.SPARSE
typedef enum logic [AES_MODE_WIDTH-1:0] {
AES_ECB = 6'b00_0001,
AES_CBC = 6'b00_0010,
AES_CFB = 6'b00_0100,
AES_OFB = 6'b00_1000,
AES_CTR = 6'b01_0000,
AES_NONE = 6'b10_0000
} aes_mode_e;
typedef enum logic [AES_OP_WIDTH-1:0] {
CIPH_FWD = 2'b01,
CIPH_INV = 2'b10
} ciph_op_e;
// SEC_CM: MAIN.CONFIG.SPARSE
typedef enum logic [AES_KEYLEN_WIDTH-1:0] {
AES_128 = 3'b001,
AES_192 = 3'b010,
AES_256 = 3'b100
} key_len_e;
// SEC_CM: MAIN.CONFIG.SPARSE
typedef enum logic [AES_PRNGRESEEDRATE_WIDTH-1:0] {
PER_1 = 3'b001,
PER_64 = 3'b010,
PER_8K = 3'b100
} prs_rate_e;
parameter int unsigned BlockCtrWidth = 13;
typedef struct packed {
logic [31:7] unused;
logic alert_fatal_fault;
logic alert_recov_ctrl_update_err;
logic input_ready;
logic output_valid;
logic output_lost;
logic stall;
logic idle;
} status_t;
typedef struct packed {
logic recov_ctrl_update_err;
logic fatal_fault;
} alert_test_t;
// Sparse state encodings
// Encoding generated with:
// $ ./util/design/sparse-fsm-encode.py -d 3 -m 8 -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
// Minimum Hamming weight: 1
// Maximum Hamming weight: 5
//
localparam int CipherCtrlStateWidth = 6;
typedef enum logic [CipherCtrlStateWidth-1:0] {
CIPHER_CTRL_IDLE = 6'b001001,
CIPHER_CTRL_INIT = 6'b100011,
CIPHER_CTRL_ROUND = 6'b111101,
CIPHER_CTRL_FINISH = 6'b010000,
CIPHER_CTRL_PRNG_RESEED = 6'b100100,
CIPHER_CTRL_CLEAR_S = 6'b111010,
CIPHER_CTRL_CLEAR_KD = 6'b001110,
CIPHER_CTRL_ERROR = 6'b010111
} aes_cipher_ctrl_e;
// $ ./sparse-fsm-encode.py -d 3 -m 3 -n 5 \
// -s 31468618 --language=sv
//
// Hamming distance histogram:
//
// 0: --
// 1: --
// 2: --
// 3: |||||||||||||||||||| (66.67%)
// 4: |||||||||| (33.33%)
// 5: --
//
// Minimum Hamming distance: 3
// Maximum Hamming distance: 4
//
localparam int CtrStateWidth = 5;
typedef enum logic [CtrStateWidth-1:0] {
CTR_IDLE = 5'b01110,
CTR_INCR = 5'b11000,
CTR_ERROR = 5'b00001
} aes_ctr_e;
// Encoding generated with:
// $ ./util/design/sparse-fsm-encode.py -d 3 -m 8 -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
// Minimum Hamming weight: 1
// Maximum Hamming weight: 5
//
localparam int CtrlStateWidth = 6;
typedef enum logic [CtrlStateWidth-1:0] {
CTRL_IDLE = 6'b001001,
CTRL_LOAD = 6'b100011,
CTRL_PRNG_UPDATE = 6'b111101,
CTRL_PRNG_RESEED = 6'b010000,
CTRL_FINISH = 6'b100100,
CTRL_CLEAR_I = 6'b111010,
CTRL_CLEAR_CO = 6'b001110,
CTRL_ERROR = 6'b010111
} aes_ctrl_e;
// Generic, sparse mux selector encodings
// Encoding generated with:
// $ ./util/design/sparse-fsm-encode.py -d 3 -m 2 -n 3 \
// -s 31468618 --language=sv
//
// Hamming distance histogram:
//
// 0: --
// 1: --
// 2: --
// 3: |||||||||||||||||||| (100.00%)
//
// Minimum Hamming distance: 3
// Maximum Hamming distance: 3
// Minimum Hamming weight: 1
// Maximum Hamming weight: 2
//
parameter int Mux2SelWidth = 3;
typedef enum logic [Mux2SelWidth-1:0] {
MUX2_SEL_0 = 3'b011,
MUX2_SEL_1 = 3'b100
} mux2_sel_e;
// Encoding generated with:
// $ ./sparse-fsm-encode.py -d 3 -m 3 -n 5 \
// -s 31468618 --language=sv
//
// Hamming distance histogram:
//
// 0: --
// 1: --
// 2: --
// 3: |||||||||||||||||||| (66.67%)
// 4: |||||||||| (33.33%)
// 5: --
//
// Minimum Hamming distance: 3
// Maximum Hamming distance: 4
//
parameter int Mux3SelWidth = 5;
typedef enum logic [Mux3SelWidth-1:0] {
MUX3_SEL_0 = 5'b01110,
MUX3_SEL_1 = 5'b11000,
MUX3_SEL_2 = 5'b00001
} mux3_sel_e;
// Encoding generated with:
// $ ./sparse-fsm-encode.py -d 3 -m 4 -n 5 \
// -s 31468618 --language=sv
//
// Hamming distance histogram:
//
// 0: --
// 1: --
// 2: --
// 3: |||||||||||||||||||| (66.67%)
// 4: |||||||||| (33.33%)
// 5: --
//
// Minimum Hamming distance: 3
// Maximum Hamming distance: 4
//
parameter int Mux4SelWidth = 5;
typedef enum logic [Mux4SelWidth-1:0] {
MUX4_SEL_0 = 5'b01110,
MUX4_SEL_1 = 5'b11000,
MUX4_SEL_2 = 5'b00001,
MUX4_SEL_3 = 5'b10111
} mux4_sel_e;
// $ ./sparse-fsm-encode.py -d 3 -m 6 -n 6 \
// -s 31468618 --language=sv
//
// Hamming distance histogram:
//
// 0: --
// 1: --
// 2: --
// 3: |||||||||||||||||||| (53.33%)
// 4: ||||||||||||||| (40.00%)
// 5: || (6.67%)
// 6: --
//
// Minimum Hamming distance: 3
// Maximum Hamming distance: 5
//
parameter int Mux6SelWidth = 6;
typedef enum logic [Mux6SelWidth-1:0] {
MUX6_SEL_0 = 6'b011101,
MUX6_SEL_1 = 6'b110000,
MUX6_SEL_2 = 6'b001000,
MUX6_SEL_3 = 6'b000011,
MUX6_SEL_4 = 6'b111110,
MUX6_SEL_5 = 6'b100101
} mux6_sel_e;
// Mux selector signal types. These use the generic types defined above.
parameter int DIPSelNum = 2;
parameter int DIPSelWidth = Mux2SelWidth;
typedef enum logic [DIPSelWidth-1:0] {
DIP_DATA_IN = MUX2_SEL_0,
DIP_CLEAR = MUX2_SEL_1
} dip_sel_e;
parameter int SISelNum = 2;
parameter int SISelWidth = Mux2SelWidth;
typedef enum logic [SISelWidth-1:0] {
SI_ZERO = MUX2_SEL_0,
SI_DATA = MUX2_SEL_1
} si_sel_e;
parameter int AddSISelNum = 2;
parameter int AddSISelWidth = Mux2SelWidth;
typedef enum logic [AddSISelWidth-1:0] {
ADD_SI_ZERO = MUX2_SEL_0,
ADD_SI_IV = MUX2_SEL_1
} add_si_sel_e;
parameter int StateSelNum = 3;
parameter int StateSelWidth = Mux3SelWidth;
typedef enum logic [StateSelWidth-1:0] {
STATE_INIT = MUX3_SEL_0,
STATE_ROUND = MUX3_SEL_1,
STATE_CLEAR = MUX3_SEL_2
} state_sel_e;
parameter int AddRKSelNum = 3;
parameter int AddRKSelWidth = Mux3SelWidth;
typedef enum logic [AddRKSelWidth-1:0] {
ADD_RK_INIT = MUX3_SEL_0,
ADD_RK_ROUND = MUX3_SEL_1,
ADD_RK_FINAL = MUX3_SEL_2
} add_rk_sel_e;
parameter int KeyInitSelNum = 3;
parameter int KeyInitSelWidth = Mux3SelWidth;
typedef enum logic [KeyInitSelWidth-1:0] {
KEY_INIT_INPUT = MUX3_SEL_0,
KEY_INIT_KEYMGR = MUX3_SEL_1,
KEY_INIT_CLEAR = MUX3_SEL_2
} key_init_sel_e;
parameter int IVSelNum = 6;
parameter int IVSelWidth = Mux6SelWidth;
typedef enum logic [IVSelWidth-1:0] {
IV_INPUT = MUX6_SEL_0,
IV_DATA_OUT = MUX6_SEL_1,
IV_DATA_OUT_RAW = MUX6_SEL_2,
IV_DATA_IN_PREV = MUX6_SEL_3,
IV_CTR = MUX6_SEL_4,
IV_CLEAR = MUX6_SEL_5
} iv_sel_e;
parameter int KeyFullSelNum = 4;
parameter int KeyFullSelWidth = Mux4SelWidth;
typedef enum logic [KeyFullSelWidth-1:0] {
KEY_FULL_ENC_INIT = MUX4_SEL_0,
KEY_FULL_DEC_INIT = MUX4_SEL_1,
KEY_FULL_ROUND = MUX4_SEL_2,
KEY_FULL_CLEAR = MUX4_SEL_3
} key_full_sel_e;
parameter int KeyDecSelNum = 2;
parameter int KeyDecSelWidth = Mux2SelWidth;
typedef enum logic [KeyDecSelWidth-1:0] {
KEY_DEC_EXPAND = MUX2_SEL_0,
KEY_DEC_CLEAR = MUX2_SEL_1
} key_dec_sel_e;
parameter int KeyWordsSelNum = 4;
parameter int KeyWordsSelWidth = Mux4SelWidth;
typedef enum logic [KeyWordsSelWidth-1:0] {
KEY_WORDS_0123 = MUX4_SEL_0,
KEY_WORDS_2345 = MUX4_SEL_1,
KEY_WORDS_4567 = MUX4_SEL_2,
KEY_WORDS_ZERO = MUX4_SEL_3
} key_words_sel_e;
parameter int RoundKeySelNum = 2;
parameter int RoundKeySelWidth = Mux2SelWidth;
typedef enum logic [RoundKeySelWidth-1:0] {
ROUND_KEY_DIRECT = MUX2_SEL_0,
ROUND_KEY_MIXED = MUX2_SEL_1
} round_key_sel_e;
parameter int AddSOSelNum = 3;
parameter int AddSOSelWidth = Mux3SelWidth;
typedef enum logic [AddSOSelWidth-1:0] {
ADD_SO_ZERO = MUX3_SEL_0,
ADD_SO_IV = MUX3_SEL_1,
ADD_SO_DIP = MUX3_SEL_2
} add_so_sel_e;
// Sparse two-value signal type sp2v_e
parameter int Sp2VNum = 2;
parameter int Sp2VWidth = Mux2SelWidth;
typedef enum logic [Sp2VWidth-1:0] {
SP2V_HIGH = MUX2_SEL_0,
SP2V_LOW = MUX2_SEL_1
} sp2v_e;
typedef logic [Sp2VWidth-1:0] sp2v_logic_t;
parameter sp2v_logic_t SP2V_LOGIC_HIGH = {SP2V_HIGH};
// Control register type
typedef struct packed {
logic manual_operation;
prs_rate_e prng_reseed_rate;
logic sideload;
key_len_e key_len;
aes_mode_e mode;
aes_op_e operation;
} ctrl_reg_t;
parameter ctrl_reg_t CTRL_RESET = '{
manual_operation: aes_reg_pkg::AES_CTRL_SHADOWED_MANUAL_OPERATION_RESVAL,
prng_reseed_rate: prs_rate_e'(aes_reg_pkg::AES_CTRL_SHADOWED_PRNG_RESEED_RATE_RESVAL),
sideload: aes_reg_pkg::AES_CTRL_SHADOWED_SIDELOAD_RESVAL,
key_len: key_len_e'(aes_reg_pkg::AES_CTRL_SHADOWED_KEY_LEN_RESVAL),
mode: aes_mode_e'(aes_reg_pkg::AES_CTRL_SHADOWED_MODE_RESVAL),
operation: aes_op_e'(aes_reg_pkg::AES_CTRL_SHADOWED_OPERATION_RESVAL)
};
// Multiplication by {02} (i.e. x) on GF(2^8)
// with field generating polynomial {01}{1b} (9'h11b)
// Sometimes also denoted by xtime().
function automatic logic [7:0] aes_mul2(logic [7:0] in);
logic [7:0] out;
out[7] = in[6];
out[6] = in[5];
out[5] = in[4];
out[4] = in[3] ^ in[7];
out[3] = in[2] ^ in[7];
out[2] = in[1];
out[1] = in[0] ^ in[7];
out[0] = in[7];
return out;
endfunction
// Multiplication by {04} (i.e. x^2) on GF(2^8)
// with field generating polynomial {01}{1b} (9'h11b)
function automatic logic [7:0] aes_mul4(logic [7:0] in);
return aes_mul2(aes_mul2(in));
endfunction
// Division by {02} (i.e. x) on GF(2^8)
// with field generating polynomial {01}{1b} (9'h11b)
// This is the inverse of aes_mul2() or xtime().
function automatic logic [7:0] aes_div2(logic [7:0] in);
logic [7:0] out;
out[7] = in[0];
out[6] = in[7];
out[5] = in[6];
out[4] = in[5];
out[3] = in[4] ^ in[0];
out[2] = in[3] ^ in[0];
out[1] = in[2];
out[0] = in[1] ^ in[0];
return out;
endfunction
// Circular byte shift to the left
function automatic logic [31:0] aes_circ_byte_shift(logic [31:0] in, logic [1:0] shift);
logic [31:0] out;
logic [31:0] s;
s = {30'b0,shift};
out = {in[8*((7-s)%4) +: 8], in[8*((6-s)%4) +: 8],
in[8*((5-s)%4) +: 8], in[8*((4-s)%4) +: 8]};
return out;
endfunction
// Transpose state matrix
function automatic logic [3:0][3:0][7:0] aes_transpose(logic [3:0][3:0][7:0] in);
logic [3:0][3:0][7:0] transpose;
transpose = '0;
for (int j = 0; j < 4; j++) begin
for (int i = 0; i < 4; i++) begin
transpose[i][j] = in[j][i];
end
end
return transpose;
endfunction
// Extract single column from state matrix
function automatic logic [3:0][7:0] aes_col_get(logic [3:0][3:0][7:0] in, logic [1:0] idx);
logic [3:0][7:0] out;
for (int i = 0; i < 4; i++) begin
out[i] = in[i][idx];
end
return out;
endfunction
// Matrix-vector multiplication in GF(2^8): c = A * b
function automatic logic [7:0] aes_mvm(
logic [7:0] vec_b,
logic [7:0] mat_a [8]
);
logic [7:0] vec_c;
vec_c = '0;
for (int i = 0; i < 8; i++) begin
for (int j = 0; j < 8; j++) begin
vec_c[i] = vec_c[i] ^ (mat_a[j][i] & vec_b[7-j]);
end
end
return vec_c;
endfunction
// Rotate integer indices
function automatic integer aes_rot_int(integer in, integer num);
integer out;
if (in == 0) begin
out = num - 1;
end else begin
out = in - 1;
end
return out;
endfunction
// Function for extracting LSBs of the per-S-Box pseudo-random data (PRD) from the output of the
// masking PRNG.
//
// 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:
//
// prng_output = { 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.
// For one row of the state matrix, extract the 8 LSBs of the per-S-Box PRD from the PRNG output.
// These bits are used as:
// - input data masks, and
// - SubBytes output mask when using a masked Canright S-Box implementation.
function automatic logic [3:0][7:0] aes_prd_get_lsbs(
logic [(4*WidthPRDSBox)-1:0] in
);
logic [3:0][7:0] prd_lsbs;
for (int i = 0; i < 4; i++) begin
prd_lsbs[i] = in[i*WidthPRDSBox +: 8];
end
return prd_lsbs;
endfunction
endpackage