blob: 0f49d6c405cd4568874442b7e0b6d02d01109efb [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// kmac_pkg
package kmac_pkg;
parameter int MsgWidth = sha3_pkg::MsgWidth;
parameter int MsgStrbW = sha3_pkg::MsgStrbW;
// Message FIFO depth
//
// Assume entropy is ready always (if Share is reused as an entropy in Chi)
// Then it takes 72 cycles to complete the Keccak round. While Keccak is in
// operation, the module need to store the incoming messages to not degrade
// the throughput.
//
// Based on the observation from HMAC case, the core usually takes 5 clocks
// to fetch data and store into KMAC. So the core can push at most 14.5 X 4B
// which is 58B. After that, Keccak can fetch the data from MSG_FIFO faster
// rate than the core can push. To fetch 58B, it takes around 7~8 cycles.
// For that time, the core only can push at most 2 DW. After that Keccak
// waits the incoming message.
//
// So Message FIFO doesn't need full block size except the KMAC case, which
// is delayed the operation by processing Function Name N, customization S,
// and secret keys. But KMAC doesn't need high throughput anyway (72Mb/s).
parameter int RegIntfWidth = 32; // 32bit interface
parameter int RegLatency = 5; // 5 cycle to write one Word
parameter int Sha3Latency = 72; // Expected masked sha3 processing time 24x3
// Total required buffer size while SHA3 is in processing
parameter int BufferCycles = (Sha3Latency + RegLatency - 1)/RegLatency;
parameter int BufferSizeBits = RegIntfWidth * BufferCycles;
// Required MsgFifoDepth. Adding slightly more buffer for margin
parameter int MsgFifoDepth = 2 + ((BufferSizeBits + MsgWidth - 1)/MsgWidth);
parameter int MsgFifoDepthW = $clog2(MsgFifoDepth+1);
parameter int MsgWindowWidth = 32; // Register width
parameter int MsgWindowDepth = 512; // 2kB space
// Key related definitions
// If this value is changed, please modify the logic inside kmac_core
// that assigns the value into `encoded_key`
parameter int MaxKeyLen = 512;
// size of encode_string(Key)
// $ceil($clog2(MaxKeyLen+1)/8)
parameter int MaxEncodedKeyLenW = $clog2(MaxKeyLen+1);
parameter int MaxEncodedKeyLenByte = (MaxEncodedKeyLenW + 8 - 1) / 8;
parameter int MaxEncodedKeyLenSize = MaxEncodedKeyLenByte * 8;
// Secret Key left_encode(len(Key))
// ---------- ------------------------
parameter int MaxEncodedKeyW = MaxKeyLen + MaxEncodedKeyLenSize + 8;
// key_len is SW configurable CSR.
// Current KMAC allows 5 key length options.
// This value determines the KMAC core how to map the value
// from Secret Key register to key size block
typedef enum logic [2:0] {
Key128 = 3'b 000, // 128 bit secret key
Key192 = 3'b 001, // 192 bit secret key
Key256 = 3'b 010, // 256 bit secret key
Key384 = 3'b 011, // 384 bit secret key
Key512 = 3'b 100 // 512 bit secret key
} key_len_e;
// kmac_cmd_e defines the possible command sets that software issues via
// !!CMD register. This is mainly to limit the error scenario that SW writes
// multiple commands at once. Additionally they are sparse encoded to harden
// against FI attacks
//
// Encoding generated with:
// $ ./util/design/sparse-fsm-encode.py -d 3 -m 5 -n 6 \
// -s 1891656028 --language=sv
//
// Hamming distance histogram:
//
// 0: --
// 1: --
// 2: --
// 3: |||||||||||||||||||| (50.00%)
// 4: |||||||||||||||| (40.00%)
// 5: |||| (10.00%)
// 6: --
//
// Minimum Hamming distance: 3
// Maximum Hamming distance: 5
// Minimum Hamming weight: 3
// Maximum Hamming weight: 4
//
typedef enum logic [5:0] {
//CmdNone = 6'b001011, // dec 10
// CmdNone is manually set to all zero by design!
// The minimum Hamming distance is still 3
CmdNone = 6'b000000, // dec 0
CmdStart = 6'b011101, // dec 29
CmdProcess = 6'b101110, // dec 46
CmdManualRun = 6'b110001, // dec 49
CmdDone = 6'b010110 // dec 22
} kmac_cmd_e;
// Timer
parameter int unsigned TimerPrescalerW = 10;
parameter int unsigned EdnWaitTimerW = 16;
// Entropy Mode Selection : Should be matched to register package Enum value
typedef enum logic [1:0] {
EntropyModeNone = 2'h 0,
EntropyModeEdn = 2'h 1,
EntropyModeSw = 2'h 2
} entropy_mode_e;
// PRNG (kmac_entropy)
parameter int unsigned EntropyLfsrW = 800;
parameter int unsigned ChunkSizeEntropyLfsr = 32;
parameter int unsigned NumChunksEntropyLfsr = EntropyLfsrW / ChunkSizeEntropyLfsr;
// 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 800 --seed 3369807298 --prefix ""
typedef logic [EntropyLfsrW-1:0] lfsr_seed_t;
typedef logic [EntropyLfsrW-1:0][$clog2(EntropyLfsrW)-1:0] lfsr_perm_t;
parameter lfsr_seed_t RndCnstLfsrSeedDefault = {
32'h34a19ca3,
256'he514d8e17a5630c287247dff3d354c022f581ace4b6c5736b5efa4160261ab0f,
256'h6cb2915197ab3588982bcffc9cf3b46a250cebf728c0e76f0e680420d7f428f2,
256'h092c1e308f7c8f9d8bacc20cd18fd586d58879654aa4851de224033bfdcbc578
};
parameter lfsr_perm_t RndCnstLfsrPermDefault = {
64'hb1a3e87aeb4e69f0,
256'h2d8a6ee2c9ac567b2aa401a639a2a8ea2553614c0a8daf672c06546fc0d35267,
256'hc4572024bc116458dd0f1c10a8aef5c4ad9a788968d0d7ca7345c6b8f277a5d3,
256'hec5da20f261826ed3c8992724e70db897060be51b07a96902e14a42d12d320f8,
256'h187049b6c25f35d0e485cc4b9ef01dad2865b5e558926f380718b74394fe0f82,
256'hd5395a7d0aa4845af814e8681107a4c793758572c9467493bf1248a48f1b40c2,
256'h09319b55111d0401819685a43a06f0da441021a8c220b14f01d44e49c1683a82,
256'hafeb980964aa050641f4205131d9d4741eb5dd658e603b8ed438cb1096628d42,
256'h62c9d75ced78ed09a3ddbb60f533eef10aa5a54b478d61a06a4b326eb3402105,
256'hc27d562c6d91b48440d6d06e543be9871628a4aa9b3d2e51fa0ac2eb89a17f6d,
256'h207ad96caf25d1fcffab210c1aff12252346fe4d56a7cd9b8605c7fa638895a9,
256'h60158cd3a1ce4f2f6cf5d48579ac14b1e5219ca8914e0507b635dc712554f6bb,
256'h0ae412943a7596f4644a0c13646adc91d02c406a10d232791d3de9919eec5424,
256'haa2cac5f556c15c647eb29365062daf6aa848e10b3f665abccca713036d9f1cb,
256'h1c9bd4aaeb19c5ac01b1805e0d5479860870da49a55e8f386ca8232c728e2f61,
256'h3007aa420758818e5312401372eaa00d21c70c7e1158d2e08a1b6ac0b820cb67,
256'hf0ba4b5c0865ff04f0f9d0175817c65d81918e43e14b2f83d574bfa9c6e6deae,
256'h64c22c2974a1d5c55e2367004b249d5a02fc566685ea33b6f73aaa0244b34412,
256'hb1a12230adb1748dc1d956f9f10c8e1aa52f4702e06a16680d92226c830ec4ce,
256'h4c2eead21f08c387c3f1de89eb33b983c748e848f68b54f256715221177c5a4a,
256'h0a47d82741955626755ba1cc24e2ba40504111b9e26136be714c5bc0d330c3f7,
256'h75e863de763270a993890d633c6897218e151943edd8b79ae145cf564b774613,
256'h0b0a76c40e7e84c876640dc78260c09a85e92e5ab56c22c0e72a8669fe88ba10,
256'h8b99e437c776f0cea0d144f285b6ab7259e12284f380ae3410171cd6a8b04415,
256'he95081c8c57e3e526ad5b38019a5c1b5505540462157e7c7e68e6a6a16ac460a,
256'h5d5578da28092c7cc927cb9c0ed614a79b0e32b4c5b6a269a40743bef42b5e29,
256'hd9a75ecb5548a29e9d34ddda07c8404aabbf5479456731ece3785f6090c3f862,
256'h6eb1a5119e8b8e56b1455d820b46e20e15bb7d185a636b10ab8565732c59a302,
256'h329925186604edbd5029a9f865268e90003b5b69d3e99240c3432291a60c62a4,
256'hebad1ed028cd021b27260db22089e0c44481b1a4c120134ac63dc52fbc4cafb2,
256'he065add2665fb361665267b53024329d96587d661f724171155ee73a3f0c47a8,
256'h149751a5903c8bbcaf1782e415dfda531eb2af67c25e190330a12000e1fbb9cd
};
// These LFSR parameters have been generated with
// $ ./util/design/gen-lfsr-seed.py --width 32 --seed 2336700764 --prefix ""
parameter int LfsrFwdWidth = 32;
typedef logic [LfsrFwdWidth-1:0][$clog2(LfsrFwdWidth)-1:0] lfsr_fwd_perm_t;
parameter lfsr_fwd_perm_t RndCnstLfsrFwdPermDefault = {
160'h7f3ac6d173d78678d84908157fba482e76685704
};
// Message permutation
// These LFSR parameters have been generated with
// $ ./util/design/gen-lfsr-seed.py --width 64 --seed 1201202158 --prefix ""
// And changed the type name from lfsr_perm_t to msg_perm_t
typedef logic [MsgWidth-1:0][$clog2(MsgWidth)-1:0] msg_perm_t;
parameter msg_perm_t RndCnstMsgPermDefault = {
128'h382af41849db4cfb9c885f72f118c102,
256'hcb5526978defac799192f65f54148379af21d7e10d82a5a33c3f31a1eaf964b8
};
///////////////////////////
// Application interface //
///////////////////////////
// Number of the application interface
// Currently KMAC has three interface.
// 0: KeyMgr
// 1: LC_CTRL
// 2: ROM_CTRL
// Make sure to change `width` of app inter-module signal definition
// if this value is changed.
parameter int unsigned NumAppIntf = 3;
// Application Algorithm
// Each interface can choose algorithms among SHA3, cSHAKE, KMAC
typedef enum bit [1:0] {
// SHA3 mode doer not nees any additional information.
// Prefix will be tied to all zero and not used.
AppSHA3 = 0,
// In CShake/ KMAC mode, the Prefix can be determined by the compile-time
// parameter or through CSRs.
AppCShake = 1,
// In KMAC mode, the secret key always comes from sideload.
// KMAC mode needs uniformly distributed entropy. The request will be
// silently discarded in Reset state.
AppKMAC = 2
} app_mode_e;
// Predefined encoded_string
parameter logic [15:0] EncodedStringEmpty = 16'h 0001;
parameter logic [47:0] EncodedStringKMAC = 48'h 4341_4D4B_2001;
// encoded_string("LC_CTRL")
parameter logic [71:0] EncodedStringLcCtrl = 72'h 4c_5254_435f_434C_3801;
// encoded_string("ROM_CTRL")
parameter logic [79:0] EncodedStringRomCtrl = 80'h 4c52_5443_5f4d_4f52_4001;
parameter int unsigned NSPrefixW = sha3_pkg::NSRegisterSize*8;
typedef struct packed {
app_mode_e Mode;
sha3_pkg::keccak_strength_e Strength;
// PrefixMode determines the origin value of Prefix that is used in KMAC
// and cSHAKE operations.
// Choose **0** for CSRs (!!PREFIX), or **1** to use `Prefix` parameter
// below.
bit PrefixMode;
// If `PrefixMode` is 1'b 1, then this `Prefix` value will be used in
// cSHAKE or KMAC operation.
logic [NSPrefixW-1:0] Prefix;
} app_config_t;
parameter app_config_t AppCfg [NumAppIntf] = '{
// KeyMgr
'{
Mode: AppKMAC, // KeyMgr uses KMAC operation
Strength: sha3_pkg::L256,
PrefixMode: 1'b 1, // Use prefix parameter
// {fname: encoded_string("KMAC"), custom_str: encoded_string("")}
Prefix: NSPrefixW'({EncodedStringEmpty, EncodedStringKMAC})
},
// LC_CTRL
'{
Mode: AppCShake,
Strength: sha3_pkg::L128,
PrefixMode: 1'b 1, // Use prefix parameter
// {fname: encode_string(""), custom_str: encode_string("LC_CTRL")}
Prefix: NSPrefixW'({EncodedStringLcCtrl, EncodedStringEmpty})
},
// ROM_CTRL
'{
Mode: AppCShake,
Strength: sha3_pkg::L256,
PrefixMode: 1'b 1, // Use prefix parameter
// {fname: encode_string(""), custom_str: encode_string("ROM_CTRL")}
Prefix: NSPrefixW'({EncodedStringRomCtrl, EncodedStringEmpty})
}
};
// Exporting the app internal mux selection enum into the package. So that DV
// can use this enum in its scoreboard.
// Encoding generated with:
// $ ./util/design/sparse-fsm-encode.py -d 3 -m 4 -n 5 \
// -s 713832113 --language=sv
//
// Hamming distance histogram:
//
// 0: --
// 1: --
// 2: --
// 3: |||||||||||||||||||| (66.67%)
// 4: |||||||||| (33.33%)
// 5: --
//
// Minimum Hamming distance: 3
// Maximum Hamming distance: 4
// Minimum Hamming weight: 1
// Maximum Hamming weight: 4
//
localparam int AppMuxWidth = 5;
typedef enum logic [AppMuxWidth-1:0] {
SelNone = 5'b10100,
SelApp = 5'b11001,
SelOutLen = 5'b00010,
SelSw = 5'b01111
} app_mux_sel_e ;
// MsgWidth : 64
// MsgStrbW : 8
parameter int unsigned AppDigestW = 384;
parameter int unsigned AppKeyW = 256;
typedef struct packed {
logic valid;
logic [MsgWidth-1:0] data;
logic [MsgStrbW-1:0] strb;
logic last;
} app_req_t;
typedef struct packed {
logic ready;
logic done;
logic [AppDigestW-1:0] digest_share0;
logic [AppDigestW-1:0] digest_share1;
// Error is valid when done is high. If any error occurs during KDF, KMAC
// returns the garbage digest data with error. The KeyMgr discards the
// digest and may re-initiate the process.
logic error;
} app_rsp_t;
parameter app_req_t APP_REQ_DEFAULT = '{
valid: 1'b 0,
data: '0,
strb: '0,
last: 1'b 0
};
parameter app_rsp_t APP_RSP_DEFAULT = '{
ready: 1'b1,
done: 1'b1,
digest_share0: AppDigestW'(32'hDEADBEEF),
digest_share1: AppDigestW'(32'hFACEBEEF),
error: 1'b1
};
////////////////////
// Error Handling //
////////////////////
// Error structure is same to the SHA3 one. The codes do not overlap.
typedef enum logic [7:0] {
ErrNone = 8'h 00,
// ErrSha3SwControl occurs when software sent wrong flow signal.
// e.g) Sw set `process_i` without `start_i`. The state machine ignores
// the signal and report through the error FIFO.
//ErrSha3SwControl = 8'h 80
// ErrKeyNotValid: KeyMgr interface raises an error if the secret key is
// not valid when KeyMgr initiates KDF.
ErrKeyNotValid = 8'h 01,
// ErrSwPushMsgFifo: Sw writes data into Msg FIFO abruptly.
// This error occurs in below scenario:
// - Sw does not send "Start" command to KMAC then writes data into
// Msg FIFO
// - Sw writes data into Msg FIFO when KeyMgr is in operation
ErrSwPushedMsgFifo = 8'h 02,
// ErrSwIssuedCmdInAppActive
// - Sw writes any command while AppIntf is in active.
ErrSwIssuedCmdInAppActive = 8'h 03,
// ErrWaitTimerExpired
// Entropy Wait timer expired. Something wrong on EDN i/f
ErrWaitTimerExpired = 8'h 04,
// ErrIncorrectEntropyMode
// Incorrect Entropy mode when entropy is ready
ErrIncorrectEntropyMode = 8'h 05,
// ErrUnexpectedModeStrength
ErrUnexpectedModeStrength = 8'h 06,
// ErrIncorrectFunctionName "KMAC"
ErrIncorrectFunctionName = 8'h 07,
// ErrSwCmdSequence
ErrSwCmdSequence = 8'h 08,
// ErrSwHashingWithoutEntropyReady
// - Sw issues KMAC op without Entropy setting.
ErrSwHashingWithoutEntropyReady = 8'h 09,
// Error Shadow register update
ErrShadowRegUpdate = 8'h C0,
// Error due to lc_escalation_en_i or fatal fault
ErrFatalError = 8'h C1,
// Error due to the counter integrity check failure inside MsgFifo.Packer
ErrPackerIntegrity = 8'h C2,
// Error due to the counter integrity check failure inside MsgFifo.Fifo
ErrMsgFifoIntegrity = 8'h C3
} err_code_e;
typedef struct packed {
logic valid;
err_code_e code; // Type of error
logic [23:0] info; // Additional Debug info
} err_t;
parameter int unsigned ErrInfoW = 24 ; // err_t::info
typedef struct packed {
logic [AppDigestW-1:0] digest_share0;
logic [AppDigestW-1:0] digest_share1;
} rsp_digest_t;
///////////////////////
// Library Functions //
///////////////////////
// Endian conversion functions (32-bit, 64-bit)
function automatic logic [31:0] conv_endian32( input logic [31:0] v, input logic swap);
logic [31:0] conv_data = {<<8{v}};
conv_endian32 = (swap) ? conv_data : v ;
endfunction : conv_endian32
function automatic logic [63:0] conv_endian64( input logic [63:0] v, input logic swap);
logic [63:0] conv_data = {<<8{v}};
conv_endian64 = (swap) ? conv_data : v ;
endfunction : conv_endian64
endpackage : kmac_pkg