|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | #include "sw/device/lib/base/mmio.h" | 
|  | #include "sw/device/lib/dif/dif_clkmgr.h" | 
|  | #include "sw/device/lib/dif/dif_kmac.h" | 
|  | #include "sw/device/lib/runtime/log.h" | 
|  | #include "sw/device/lib/testing/test_framework/check.h" | 
|  | #include "sw/device/lib/testing/test_framework/ottf_main.h" | 
|  |  | 
|  | #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" | 
|  |  | 
|  | static dif_clkmgr_t clkmgr; | 
|  | static dif_kmac_t kmac; | 
|  |  | 
|  | OTTF_DEFINE_TEST_CONFIG(); | 
|  |  | 
|  | const dif_clkmgr_hintable_clock_t kmac_clock = | 
|  | kTopEarlgreyHintableClocksMainKmac; | 
|  |  | 
|  | // Digest lengths in 32-bit words. | 
|  | #define DIGEST_LEN_SHA3_256 (256 / 32) | 
|  | #define DIGEST_LEN_SHA3_512 (512 / 32) | 
|  | #define DIGEST_LEN_SHA3_MAX DIGEST_LEN_SHA3_512 | 
|  |  | 
|  | // SHA-3 test description. | 
|  | typedef struct sha3_test { | 
|  | dif_kmac_mode_sha3_t mode; | 
|  |  | 
|  | const char *message; | 
|  | size_t message_len; | 
|  |  | 
|  | const uint32_t digest[DIGEST_LEN_SHA3_MAX]; | 
|  | size_t digest_len; | 
|  | } sha3_test_t; | 
|  |  | 
|  | // SHA-3 test. | 
|  | const sha3_test_t sha3_256_test = { | 
|  | // Example taken from NIST FIPS-202 Algorithm Test Vectors: | 
|  | // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/sha3/sha-3bytetestvectors.zip | 
|  | .mode = kDifKmacModeSha3Len256, | 
|  | .message = "\xe7\x37\x21\x05", | 
|  | .message_len = 4, | 
|  | .digest = {0x8ab6423a, 0x8cf279b0, 0x52c7a34c, 0x90276f29, 0x78fec406, | 
|  | 0xd979ebb1, 0x057f7789, 0xae46401e}, | 
|  | .digest_len = DIGEST_LEN_SHA3_256}; | 
|  |  | 
|  | static void check_clock_state(dif_toggle_t expected_clock_state) { | 
|  | dif_toggle_t clock_state; | 
|  | CHECK_DIF_OK( | 
|  | dif_clkmgr_hintable_clock_get_enabled(&clkmgr, kmac_clock, &clock_state)); | 
|  | CHECK(clock_state == expected_clock_state, | 
|  | "Clock enabled state is not as expected (%d).", expected_clock_state); | 
|  | } | 
|  |  | 
|  | static void do_sha3_test(void) { | 
|  | dif_kmac_operation_state_t kmac_operation_state; | 
|  | // Run SHA3 test case using single blocking absorb/squeeze operations. | 
|  | CHECK_DIF_OK(dif_kmac_mode_sha3_start(&kmac, &kmac_operation_state, | 
|  | sha3_256_test.mode)); | 
|  |  | 
|  | // Set hint and check clk state remains enabled as KMAC is now not idle. | 
|  | CHECK_DIF_OK(dif_clkmgr_hintable_clock_set_hint(&clkmgr, kmac_clock, | 
|  | kDifToggleDisabled)); | 
|  | check_clock_state(kDifToggleEnabled); | 
|  |  | 
|  | CHECK_DIF_OK(dif_kmac_absorb(&kmac, &kmac_operation_state, | 
|  | sha3_256_test.message, sha3_256_test.message_len, | 
|  | NULL)); | 
|  |  | 
|  | uint32_t out[DIGEST_LEN_SHA3_MAX]; | 
|  | CHECK_DIF_OK(dif_kmac_squeeze(&kmac, &kmac_operation_state, out, | 
|  | sha3_256_test.digest_len, NULL)); | 
|  |  | 
|  | // Check clock state again which should still be enabled. | 
|  | check_clock_state(kDifToggleEnabled); | 
|  |  | 
|  | CHECK_DIF_OK(dif_kmac_end(&kmac, &kmac_operation_state)); | 
|  |  | 
|  | // Check the clock is now stopped. | 
|  | check_clock_state(kDifToggleDisabled); | 
|  |  | 
|  | // Check the result to be sure the SHA3 operation completed correctly. | 
|  | CHECK_ARRAYS_EQ(out, sha3_256_test.digest, sha3_256_test.digest_len, | 
|  | "Digest mismatch for test SHA3 256."); | 
|  |  | 
|  | // Set hint to enabled again to check that clock can be re-enabled. | 
|  | CHECK_DIF_OK(dif_clkmgr_hintable_clock_set_hint(&clkmgr, kmac_clock, | 
|  | kDifToggleEnabled)); | 
|  | check_clock_state(kDifToggleEnabled); | 
|  | } | 
|  |  | 
|  | bool test_main(void) { | 
|  | CHECK_DIF_OK(dif_clkmgr_init( | 
|  | mmio_region_from_addr(TOP_EARLGREY_CLKMGR_AON_BASE_ADDR), &clkmgr)); | 
|  |  | 
|  | // Get initial hint and enable for KMAC clock and check both are enabled. | 
|  | dif_toggle_t clock_hint_state; | 
|  | CHECK_DIF_OK(dif_clkmgr_hintable_clock_get_hint(&clkmgr, kmac_clock, | 
|  | &clock_hint_state)); | 
|  | CHECK(clock_hint_state == kDifToggleEnabled); | 
|  | check_clock_state(kDifToggleEnabled); | 
|  |  | 
|  | // While KMAC is not in use, set disabled hint for KMAC clock | 
|  | // then check clock state, set back to enabled and check again. | 
|  | // Note: disabled means the clock can be disabled. | 
|  | CHECK_DIF_OK(dif_clkmgr_hintable_clock_set_hint(&clkmgr, kmac_clock, | 
|  | kDifToggleDisabled)); | 
|  | check_clock_state(kDifToggleDisabled); | 
|  | CHECK_DIF_OK(dif_clkmgr_hintable_clock_set_hint(&clkmgr, kmac_clock, | 
|  | kDifToggleEnabled)); | 
|  | check_clock_state(kDifToggleEnabled); | 
|  |  | 
|  | // Initialize KMAC hardware. | 
|  | CHECK_DIF_OK( | 
|  | dif_kmac_init(mmio_region_from_addr(TOP_EARLGREY_KMAC_BASE_ADDR), &kmac)); | 
|  |  | 
|  | // Configure KMAC hardware using software entropy. | 
|  | dif_kmac_config_t config = (dif_kmac_config_t){ | 
|  | .entropy_mode = kDifKmacEntropyModeSoftware, | 
|  | .entropy_seed = {0xaa25b4bf, 0x48ce8fff, 0x5a78282a, 0x48465647, | 
|  | 0x70410fef}, | 
|  | .entropy_fast_process = kDifToggleEnabled, | 
|  | }; | 
|  | CHECK_DIF_OK(dif_kmac_configure(&kmac, config)); | 
|  |  | 
|  | // call sha3 test twice to check that when clock | 
|  | // is enabled again after the first call | 
|  | // that all still works for the second call. | 
|  |  | 
|  | do_sha3_test(); | 
|  | do_sha3_test(); | 
|  |  | 
|  | return true; | 
|  | } |