Programmer’s Guide
Initialization
The software can update the KMAC/SHA3 configurations only when the IP is in the idle state.
The software should check STATUS.sha3_idle before updating the configurations.
The software must first program CFG_SHADOWED.msg_endianness and CFG_SHADOWED.state_endianness at the initialization stage.
These determine the byte order of incoming messages (msg_endianness) and the Keccak state output (state_endianness).
Software Initiated KMAC/SHA3 process
This section describes the expected software process to run the KMAC/SHA3 HWIP.
At first, the software configures CFG_SHADOWED.kmac_en for KMAC operation.
If KMAC is enabled, the software should configure CFG_SHADOWED.mode to cSHAKE and CFG_SHADOWED.kstrength to 128 or 256 bit security strength.
The software also updates PREFIX registers if cSHAKE mode is used.
Current design does not convert cSHAKE mode to SHAKE even if PREFIX is empty string.
It is the software’s responsibility to change the CFG_SHADOWED.mode to SHAKE in case of empty PREFIX.
The KMAC/SHA3 HWIP uses PREFIX registers as it is.
It means that the software should update PREFIX with encoded values.
If CFG_SHADOWED.kmac_en is set, the software should update the secret key.
The software prepares two shares of the secret key and selects its length in KEY_LEN then writes the shares of the secret key to KEY_SHARE0 and KEY_SHARE1 .
The two shares of the secret key are the values that represent the secret key value when they are XORed together.
The software can XOR the unmasked secret key with entropy.
The XORed value is a share and the entropy used is the other share.
After configuring, the software notifies the KMAC/SHA3 engine to accept incoming messages by issuing Start command into CMD .
If Start command is not issued, the incoming message is discarded.
If KMAC is enabled, the software pushes the right_encode(output_length) value at the end of the message.
For example, if the desired output length is 256 bit, the software writes 0x00020100 to MSG_FIFO.
After the software pushes all messages, it issues Process command to CMD for SHA3 engine to complete the sponge absorbing process.
SHA3 hashing engine pads the incoming message as defined in the SHA3 specification.
After the SHA3 engine completes the sponge absorbing step, it generates kmac_done interrupt.
Or the software can poll the STATUS.squeeze bit until it becomes 1.
In this stage, the software may run the Keccak round manually.
If the desired digest length is greater than the Keccak rate, the software issues Run command for the Keccak round logic to run one full round after the software reads the current available Keccak state.
At this stage, KMAC/SHA3 does not raise an interrupt when the Keccak round completes the software initiated manual run.
The software should check STATUS.squeeze register field for the readiness of STATE value.
After the software reads all the digest values, it issues Done command to CMD register to clear the internal states.
Done command clears the Keccak state, FSM in SHA3 and KMAC, and a few internal variables.
Secret key and other software programmed values won’t be reset.
Endianness
This KMAC HWIP operates in little-endian. Internal SHA3 hashing engine receives in 64-bit granularity. The data written to SHA3 is assumed to be little endian.
The software may write/read the data in big-endian order if CFG_SHADOWED.msg_endianness or CFG_SHADOWED.state_endianness is set.
If the endianness bit is 1, the data is assumed to be big-endian.
So, the internal logic byte-swap the data.
For example, when the software writes 0xDEADBEEF with endianness as 1, the logic converts it to 0xEFBEADDE then writes into MSG_FIFO.
The software managed secret key, and the prefix are always little-endian values.
For example, if the software configures the function name N in KMAC operation, it writes encode_string("KMAC").
The encode_string("KMAC") represents 0x01 0x20 0x4b 0x4d 0x41 0x43 in byte order.
The software writes 0x4d4b2001 into PREFIX0 and 0x????4341 into PREFIX1 .
Upper 2 bytes can vary depending on the customization input string S.
EDN Entropy Mode
For regular operation, CFG_SHADOWED.entropy_mode should be set to EDN mode.
In this mode, the module automatically reseeds the internal PRNG with fresh entropy from EDN after every ENTROPY_REFRESH_THRESHOLD_SHADOWED key absorption phases in KMAC mode.
Alternatively, software can manually initiate reseeding operations using the CMD.entropy_req bit while the module is idle.
Preventing potential deadlocks in EDN mode
Under normal operating conditions, the SHA3 engine will process data a lot faster than software can push it to the Message FIFO. However, the Message FIFO may run full while the SHA3 engine is busy. In particular, this might happen because KMAC is waiting for fresh entropy from EDN. If software then tries to push further data to the Message FIFO, the processor will get stalled and if the entropy is not delivered (on time), the system may deadlock (see Empty and Full status for details).
To avoid this deadlock scenario, software should either:
- Manually trigger PRNG reseed operations after ensuring the entropy complex is up and running (recommended), or
- Check the Message FIFO depth before pushing data.
Since the latter option can be inconvenient for software, especially when processing long messages, manually triggering PRNG reseed operations is the recommended approach. In the following, both approaches are outlined in more detail.
Manually triggering PRNG reseeds
Since automatic reseeds of the internal PRNG are always triggered after the key absorption phase in KMAC mode (CFG_SHADOWED.kmac_en set to 1), and since every message in KMAC mode has only one such phase, it is sufficient for software to check the ENTROPY_REFRESH_HASH_CNT register after finishing a KMAC message.
If the value of ENTROPY_REFRESH_HASH_CNT gets sufficiently close to the value of ENTROPY_REFRESH_THRESHOLD_SHADOWED, software should:
- Ensure that the entropy complex is running.
- Check that the KMAC module is idle by reading the
STATUS.sha3_idlebit. - Trigger a manual reseed operation by setting the
CMD.entropy_reqbit. - Configure the module to process a message in cSHAKE mode (but not in KMAC mode).
More precisely, set
CFG_SHADOWED.modeto0x3andCFG_SHADOWED.kmac_ento 0. - Configure the module to use the PRNG and block any hashing operation if the PRNG is not ready by setting
CFG_SHADOWED.entropy_fast_processto 0. - Send the
startcommand to theCMDregister. The SHA3 engine will start loading and hashing the function nameNand the customization stringSfirst. - Send the
processcommand to theCMDregister. - Wait for the
STATUS.sha3_squeezebit to get set. Due to the ongoing reseed operation, theSTATUS.sha3_squeezebit should remain 0 for an extended period of time. - Send the
donecommand to theCMDregister to finish processing.
The ENTROPY_REFRESH_HASH_CNT register should now read as 0.
Note however that if the manual reseed operation is triggered while the KMAC module is busy, the reseed operation may get skipped despite the hash counter being cleared back to 0.
Checking Message FIFO depth before pushing data
Alternatively, software can avoid ever pushing data into the Message FIFO while the FIFO is full by regularly checking the FIFO depth. In particular, software can then:
- Check the FIFO depth
STATUS.fifo_depth. This represents the number of entry slots currently occupied in the FIFO. - Calculate the remaining size as (
<max number of FIFO entries> - <STATUS.fifo_depth>) * <entry size>. - Write data to fill at most the calculated remaining size.
- Repeat until all data is written.
In case the FIFO runs full (check
STATUS.fifo_full), software should check the entropy complex is running and can then optionally wait for thefifo_emptystatus interrupt before continuing.
In code, this looks something like:
/**
* Absorb input data into the Keccak computation.
*
* Assumes that the KMAC block is in the "absorb" state; it is the caller's
* responsibility to check before calling.
*
* @param in Input buffer.
* @param in_len Length of input buffer (bytes).
* @return Number of bytes written.
*/
size_t kmac_absorb(const uint8_t *in, size_t in_len) {
// Read FIFO depth from the status register.
uint32_t status = abs_mmio_read32(kBase + KMAC_STATUS_REG_OFFSET);
uint32_t fifo_depth =
bitfield_field32_read(status, KMAC_STATUS_FIFO_DEPTH_FIELD);
// Calculate the remaining space in the FIFO using auto-generated KMAC
// parameters and take the minimum of that space and the input length.
size_t free_entries = (KMAC_PARAM_NUM_ENTRIES_MSG_FIFO - fifo_depth);
size_t max_len = free_entries * KMAC_PARAM_NUM_BYTES_MSG_FIFO_ENTRY;
size_t write_len = (in_len < max_len) ? in_len : max_len;
// Note: this example uses byte-writes for simplicity, but in practice it
// would be more efficient to use word-writes for aligned full words and
// byte-writes only as needed at the beginning and end of the input.
for (size_t i = 0; i < write_len; i++) {
abs_mmio_write8(kBase + KMAC_MSG_FIFO_REG_OFFSET, in[i]);
}
return write_len;
}
Note that for modes other than KMAC, i.e., if CFG_SHADOWED.kmac_en is 0, the KMAC module will not increment the ENTROPY_REFRESH_HASH_CNT register and thus not trigger automatic reseeds.
It is safe to push to the Message FIFO without checking the STATUS.fifo_depth register.
Configuring ENTROPY_PERIOD
The ENTROPY_PERIOD register defines how long the module should wait for entropy during a PRNG reseed before triggering an error.
The configuration value should be carefully chosen based on how the entropy complex is operated.
If CSRNG is running in fully deterministic mode, any EDN request will be answered fairly quickly.
An ENTROPY_PERIOD.wait_timer value of 5000 in combination with an ENTROPY_PERIOD.prescaler value of 0 is adequate.
If CSRNG is running in regular, non-deterministic mode, it can happen that the PRNG reseed request of the KMAC module triggers a reseed request from EDN0 to CSRNG.
For Top Earlgrey, producing a single CSRNG seed value is expected to take roughly 5ms.
In the worst case, ENTROPY_SRC must first generate two more seeds to reseed all the other two CSRNG instances.
In this case, the PRNG reseed request of KMAC should get served after roughly 15ms.
If the ENTROPY_SRC is disabled, the interrupt latency and the delay for the startup health testing of the ENTROPY_SRC also need to be factored in to define the ENTROPY_PERIOD configuration value.
Leaving EDN mode
If the entropy complex becomes unavailable, software can cause the module to leave EDN mode as follows.
Note that for this to work reliably, it is recommended to configure the ENTROPY_PERIOD register to a non-zero value (see Configuring ENTROPY_PERIOD).
Otherwise, an already ongoing reseed operation may prevent the following procedure from working.
- Configure the
ENTROPY_PERIODto a sufficiently small value such aswait_timerequals 1 andprescalerequals 0, or disable EDN0 which interfaces KMAC. - Check that the KMAC module is idle by reading the
STATUS.sha3_idlebit. - Trigger a PRNG reseed operation via the
CMD.entropy_reqbit. - Wait for the entropy request to timeout and the
kmac_errinterrupt to fire. TheERR_CODEshould now readErrWaitTimerExpired. - De-assert the
CFG_SHADOWED.entropy_readybit. - Set the
CMD.err_processedbit to signal the processing of the error condition (see also Error Handling).
The FSM controlling the PRNG then goes back into its reset state and software can re-configure the desired mode in the CFG_SHADOWED.entropy_mode field and set the CFG_SHADOWED.entropy_ready bit afterwards to latch the configuration.
Error Handling
When the KMAC HW IP encounters an error, it raises the kmac_err IRQ.
SW can then read the ERR_CODE CSR to obtain more information about the error.
Having handled that IRQ, SW is expected to clear the kmac_err bit in the INTR_STATE CSR before exiting the ISR.
When SW has handled the error condition, it is expected to set the err_processed bit in the CMD CSR.
The internal SHA3 engine then flushes its FIFOs and state, which may take a few cycles.
The KMAC HW IP is ready for operation again as soon as the sha3_idle bit in the STATUS CSR is set; SW must not change the configuration of or send commands to the KMAC HW IP before that.
If the error occurred while the KMAC HW IP was being used from SW (i.e., not via an HW application interface), the kmac_done IRQ is raised when the KMAC HW IP is ready again.
KMAC/SHA3 context switching
This version of KMAC/SHA3 HWIP does support context switching enabling software to save the current hashing engine state and initiate a new high priority hashing operation. The IP enables software to restore the previous hashing state later and continue the operation.
Context switching is supported for all hashing modes.
The context
The context is the internal Keccak state that is exposed over STATE.
Software must keep this state secret as computing back to the used key is possible.
If EnMasking is enabled, the state is kept in two shares and both of them are part of the context.
Software does not need to unmask the state, saving and restoring both shares as they are is sufficient.
If EnMasking is disabled, the second share reads as zero and writes to it are ignored.
The secret key is not directly part of the context.
It has been absorbed into the Keccak state when the operation was started, so the KEY_SHARE0 and KEY_SHARE1 registers do not need to be restored.
Software must, however, restore CFG_SHADOWED to the value that was used when the context was saved.
CFG_SHADOWED.kstrength determines the block size of the remaining message and CFG_SHADOWED.mode the padding that terminates the operation.
Message block alignment
Saving a context is only possible in the absorb phase at the boundary of complete message blocks. A message block is complete when the message written since the last Start or Continue command is a multiple of the Keccak rate. The Keccak rate depends on the configured mode and security strength:
CFG_SHADOWED.mode | CFG_SHADOWED.kstrength | Block size |
|---|---|---|
| SHA3 | 224 | 144 bytes |
| SHA3 | 256 | 136 bytes |
| SHA3 | 384 | 104 bytes |
| SHA3 | 512 | 72 bytes |
| SHAKE, cSHAKE | 128 | 168 bytes |
| SHAKE, cSHAKE | 256 | 136 bytes |
Bytes that have been written but not yet absorbed are not part of the Keccak state and can therefore not be saved.
If software issues the stop command in this situation, ErrSwStopNotBlockAligned is reported, see Saving a context.
Saving a context
To save a context, software needs to follow this procedure:
- Write the
stopcommand intoCMD. - Poll
STATUS.sha3_stoppedor wait for thekmac_doneinterrupt. - Read
STATE. - Write the
donecommand intoCMD.
The last step clears the Keccak state. It prevents the context of one message stream from leaking into another one and it returns the engine into the idle state, which is required before a context can be restored.
If the message is not block aligned when the stop command is issued, ErrSwStopNotBlockAligned is reported and the absorbed data of the incomplete block is discarded.
The KMAC HWIP still enters the stopped state, so software releases it with the done command and starts the message from the beginning.
No other command is accepted in that state.
Restoring a context
To resume a previously saved context, KMAC HWIP must be idle, and software needs to follow this procedure:
- Restore
CFG_SHADOWEDto the configuration that was used when the context was saved. - In KMAC mode with masking enabled, ensure the entropy is configured by setting
CFG_SHADOWED.entropy_modeandCFG_SHADOWED.entropy_ready, as for thestartcommand. Otherwise, thecontinuecommand is discarded andErrSwHashingWithoutEntropyReadyis reported. - Write the
state_writecommand intoCMD. - Poll
STATUS.state_writeuntil it is set, or until thekmac_errinterrupt is raised (see below). - Write the saved context back into
STATE. - Write the
continuecommand intoCMD.
The state_write command claims the KMAC/SHA3 HWIP for software, preventing that an application interface takes the block over during the restore and clears the Keccak state.
Hence, writes to the STATE register are only accepted when the IP block was claimed using this command.
The command also clears the Keccak state itself, so a restore always starts from a known state and the continue command resumes only the context written after the claim.
When the application interface already claims the HWIP block, or claims it at the same time, the state_write command is discarded and ERR_CODE reports ErrSwIssuedCmdInAppActive.
STATUS.state_write is then never set, so software must not poll it without also checking for this error, as it would otherwise deadlock.
On this error, software waits until the application interface has finished its operation and issues the state_write command again.
If software decides not to resume a context after claiming the block, it can release the HWIP with the done command.
As after a completed operation, the done command clears the Keccak state.
In contrast to the start command, the continue command does not process the prefix and the secret key block again, as both are already part of the restored context.
Afterwards software writes further message blocks and either saves the context again, or finalizes the operation with the process command as described in Software Initiated KMAC/SHA3 process.
The final message block does not need to be complete.
Restrictions
Context switching is not available when a sideloaded key is used.
The Keccak function is public and invertible, so software can undo the absorb of every message block it wrote itself, one inversion per block, until it reaches the state after the secret key and recovers a key it is not supposed to know.
Saving later in the message does not help, as every state in the absorbing stage leads back to the key.
The stop, state_write, and continue commands are discarded while CFG_SHADOWED.sideload is set.
Requests from the hardware application interfaces are stalled while software holds the block through the state_write command, until it issues the done command.
The continue command does not release it.
Software must therefore also issue done on its error paths.
The following errors are reported in ERR_CODE if the procedures above are not followed:
| Error | Description |
|---|---|
ErrSwStopNotBlockAligned | The stop command was issued but the message is not a multiple of the block size. The absorb is ended anyway and the incomplete block is discarded, so the operation cannot be resumed and has to be started again. |
ErrSwSaveRestoreSideload | The stop, state_write or continue command was issued while a sideloaded key is selected. |
ErrSwIssuedCmdInAppActive | A command, for example state_write, was issued while a hardware application interface was using the block. |
ErrSwCmdSequence | A command was issued that is not allowed in the current state, e.g. run after the stop command, or continue without a preceding state_write command. |
ErrSwHashingWithoutEntropyReady | The continue command was issued in KMAC mode while masking is enabled, but the entropy was not configured. As for the start command, the command is discarded. |