| // 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/arch/device.h" | 
 | #include "sw/device/lib/base/mmio.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" | 
 |  | 
 | OTTF_DEFINE_TEST_CONFIG(); | 
 |  | 
 | /** | 
 |  * Digest lengths in 32-bit words. | 
 |  */ | 
 | #define DIGEST_LEN_SHA3_224 (224 / 32) | 
 | #define DIGEST_LEN_SHA3_256 (256 / 32) | 
 | #define DIGEST_LEN_SHA3_384 (384 / 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 tests. | 
 |  */ | 
 | const sha3_test_t sha3_tests[] = { | 
 |     // Examples 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 = kDifKmacModeSha3Len224, | 
 |         .message = NULL, | 
 |         .message_len = 0, | 
 |         .digest = {0x42034e6b, 0xb7db6736, 0x45156e3b, 0xabb10e4f, 0x9a7f59d4, | 
 |                    0x3f8e071b, 0xc76b5a5b}, | 
 |         .digest_len = DIGEST_LEN_SHA3_224, | 
 |     }, | 
 |     { | 
 |         .mode = kDifKmacModeSha3Len256, | 
 |         .message = "\xe7\x37\x21\x05", | 
 |         .message_len = 32 / 8, | 
 |         .digest = {0x8ab6423a, 0x8cf279b0, 0x52c7a34c, 0x90276f29, 0x78fec406, | 
 |                    0xd979ebb1, 0x057f7789, 0xae46401e}, | 
 |         .digest_len = DIGEST_LEN_SHA3_256, | 
 |     }, | 
 |     { | 
 |         .mode = kDifKmacModeSha3Len384, | 
 |         .message = "\xa7\x48\x47\x93\x0a\x03\xab\xee\xa4\x73\xe1\xf3\xdc\x30" | 
 |                    "\xb8\x88\x15", | 
 |         .message_len = 136 / 8, | 
 |         .digest = {0x29f9a6db, 0xd6f955fe, 0xc0675f6c, 0xf1823baf, 0xb358cf7b, | 
 |                    0x16f35267, 0x3f08165c, 0x78d48fea, 0xf20369ee, 0xd20a827f, | 
 |                    0xaf5099dd, 0x00678cb4}, | 
 |         .digest_len = DIGEST_LEN_SHA3_384, | 
 |     }, | 
 |     { | 
 |         .mode = kDifKmacModeSha3Len512, | 
 |         .message = | 
 |             "\x66\x4e\xf2\xe3\xa7\x05\x9d\xaf\x1c\x58\xca\xf5\x20\x08\xc5\x22" | 
 |             "\x7e\x85\xcd\xcb\x83\xb4\xc5\x94\x57\xf0\x2c\x50\x8d\x4f\x4f\x69" | 
 |             "\xf8\x26\xbd\x82\xc0\xcf\xfc\x5c\xb6\xa9\x7a\xf6\xe5\x61\xc6\xf9" | 
 |             "\x69\x70\x00\x52\x85\xe5\x8f\x21\xef\x65\x11\xd2\x6e\x70\x98\x89" | 
 |             "\xa7\xe5\x13\xc4\x34\xc9\x0a\x3c\xf7\x44\x8f\x0c\xae\xec\x71\x14" | 
 |             "\xc7\x47\xb2\xa0\x75\x8a\x3b\x45\x03\xa7\xcf\x0c\x69\x87\x3e\xd3" | 
 |             "\x1d\x94\xdb\xef\x2b\x7b\x2f\x16\x88\x30\xef\x7d\xa3\x32\x2c\x3d" | 
 |             "\x3e\x10\xca\xfb\x7c\x2c\x33\xc8\x3b\xbf\x4c\x46\xa3\x1d\xa9\x0c" | 
 |             "\xff\x3b\xfd\x4c\xcc\x6e\xd4\xb3\x10\x75\x84\x91\xee\xba\x60\x3a" | 
 |             "\x76", | 
 |         .message_len = 1160 / 8, | 
 |         .digest = {0xf15f82e5, 0xd570c0a3, 0xe7bb2fa5, 0x444a8511, 0x5f295405, | 
 |                    0x69797afb, 0xd10879a1, 0xbebf6301, 0xa6521d8f, 0x13a0e876, | 
 |                    0x1ca1567b, 0xb4fb0fdf, 0x9f89bc56, 0x4bd127c7, 0x322288d8, | 
 |                    0x4e919d54}, | 
 |         .digest_len = DIGEST_LEN_SHA3_512, | 
 |     }, | 
 | }; | 
 |  | 
 | #define DIGEST_LEN_SHAKE_MAX 102 | 
 |  | 
 | /** | 
 |  * SHAKE test description. | 
 |  */ | 
 | typedef struct shake_test { | 
 |   dif_kmac_mode_shake_t mode; | 
 |  | 
 |   const char *message; | 
 |   size_t message_len; | 
 |  | 
 |   const uint32_t digest[DIGEST_LEN_SHAKE_MAX]; | 
 |   size_t digest_len; | 
 | } shake_test_t; | 
 |  | 
 | /** | 
 |  * SHAKE tests. | 
 |  */ | 
 | // Examples generated using a custom Go program importing package | 
 | // `golang.org/x/crypto/sha3` | 
 | const shake_test_t shake_tests[] = { | 
 |     { | 
 |         .mode = kDifKmacModeShakeLen128, | 
 |         .message = "OpenTitan", | 
 |         .message_len = 9, | 
 |         .digest = {0x235a6522, 0x3bd735ac, 0x77832247, 0xc6b12919, 0xfb80eff0, | 
 |                    0xb8308a5a, 0xcb25db1f, 0xc5ce4cf2, 0x349730fc, 0xcedf024c, | 
 |                    0xff0eefec, 0x6985fe35, 0x3c46a736, 0x0084044b, 0x6d9f9920, | 
 |                    0x7c0ab055, 0x19d1d3ce, 0xb4353949, 0xfe8ffbcd, 0x5a7f2ec6, | 
 |                    0xc3cf795f, 0xa56d0d7b, 0x520c3358, 0x11237ec9, 0x4ca5ed53, | 
 |                    0x2999edc0, 0x6c59c68f, 0x54d9890c, 0x89a33092, 0xf406c674, | 
 |                    0xe2b4ebf1, 0x14e68bb2, 0x898ceb72, 0x1878875f, 0x9d7bb8d2, | 
 |                    0x268e4a5a, 0xe5da510f, 0x97e5d3bc, 0xaae1b7bc, 0xa337f70b, | 
 |                    0xeae3cc65, 0xb8429058, 0xe4319c08, 0xd35e2786, 0xbc99af6e, | 
 |                    0x19a04aa8, 0xccbf18bf, 0xf681ebd4, 0x3d6da575, 0x2f0b9406}, | 
 |         .digest_len = 1600 / 8 / 4,  // Rate (r) is 42 words. | 
 |     }, | 
 |     { | 
 |         .mode = kDifKmacModeShakeLen256, | 
 |         .message = "OpenTitan", | 
 |         .message_len = 9, | 
 |         .digest = {0x6a0faccd, 0xbf29cb1a, 0xb631f604, 0xdbcab36,  0xa15d167b, | 
 |                    0x18dc668b, 0x272e411b, 0x865e651a, 0x8abedb2a, 0x8db38e78, | 
 |                    0xe503c9a2, 0xe64faca9, 0xcbd867d0, 0xdba6f20f, 0xbe129db9, | 
 |                    0x842dc15c, 0x1406410b, 0x014ce621, 0x5d24eaf2, 0x63bdf816, | 
 |                    0xfb236f50, 0xbdba910c, 0xf4ba0e9a, 0x74b5a51f, 0xd644dffd, | 
 |                    0xcd650165, 0xe4ec5e7d, 0x64df5448, 0xdcf7b5e7, 0x68709c07, | 
 |                    0x47eed1db, 0xc1e55b24, 0x3c02fad9, 0xd72db62e, 0xc5a48eaf, | 
 |                    0xd14bb0c4, 0x0f7143ba, 0x4071b63e, 0x21f0ec4b, 0x41065039, | 
 |                    0x1b3e41c0, 0xd0d3b1d0, 0xca16acb9, 0xa06f55aa, 0x7bc7ce75, | 
 |                    0x08da25ce, 0x596a654b, 0x0b57ae54, 0x4b88c863, 0x199202d7, | 
 |                    0x88c112b6, 0xf6dc4a95, 0xe1cfeffa, 0xa7809e6f, 0x3a796dcd, | 
 |                    0xb5962e44, 0x179d6ff0, 0xc898c5a9, 0xd3f02195, 0x43623028, | 
 |                    0x4c3a4fe7, 0x2fab7bda, 0x04e5b4d4, 0xe0420692, 0x32fcaa2a, | 
 |                    0x05e92f07, 0xba0564ea, 0x7b169778, 0x61d4ca3e, 0x4a5d92ec, | 
 |                    0x079cb3ba, 0x9a784e40, 0x6381498c, 0xed6d8b6a, 0x2be74d42, | 
 |                    0xa234a3db, 0x60d10de8, 0xf0c77dda, 0xc8f94b72, 0x239a2bdf, | 
 |                    0xbfeba4a6, 0xc91042e9, 0xa5a11310, 0x8b44d66a, 0xea9bff2f, | 
 |                    0x441a445f, 0xe88ee35d, 0x89386c12, 0x1a8de11e, 0x46aff650, | 
 |                    0x423323c9, 0xba7b8db4, 0x06c36eb0, 0x4fd75b36, 0xf0c70001, | 
 |                    0x0aefb1df, 0x6ae399e6, 0xf71930a6, 0xdef2206,  0x5ce2a640, | 
 |                    0x6a82fcf4, 0xa91b0815}, | 
 |         .digest_len = 3264 / 8 / 4,  // Rate (r) is 34 words. | 
 |     }, | 
 | }; | 
 |  | 
 | /** | 
 |  * Run SHA-3 test cases using single blocking absorb/squeeze operations. | 
 |  */ | 
 | void run_sha3_test(dif_kmac_t *kmac) { | 
 |   dif_kmac_operation_state_t operation_state; | 
 |   for (int i = 0; i < ARRAYSIZE(sha3_tests); ++i) { | 
 |     sha3_test_t test = sha3_tests[i]; | 
 |  | 
 |     CHECK_DIF_OK(dif_kmac_mode_sha3_start(kmac, &operation_state, test.mode)); | 
 |     if (test.message_len > 0) { | 
 |       CHECK_DIF_OK(dif_kmac_absorb(kmac, &operation_state, test.message, | 
 |                                    test.message_len, NULL)); | 
 |     } | 
 |     uint32_t out[DIGEST_LEN_SHA3_MAX]; | 
 |     CHECK(DIGEST_LEN_SHA3_MAX >= test.digest_len); | 
 |     CHECK_DIF_OK( | 
 |         dif_kmac_squeeze(kmac, &operation_state, out, test.digest_len, NULL)); | 
 |     CHECK_DIF_OK(dif_kmac_end(kmac, &operation_state)); | 
 |  | 
 |     for (int j = 0; j < test.digest_len; ++j) { | 
 |       CHECK(out[j] == test.digest[j], | 
 |             "test %d: mismatch at %d got=0x%x want=0x%x", i, j, out[j], | 
 |             test.digest[j]); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | /** | 
 |  * Run a SHA-3 test case with varying alignments. | 
 |  */ | 
 | void run_sha3_alignment_test(dif_kmac_t *kmac) { | 
 |   // Examples taken from NIST FIPS-202 Algorithm Test Vectors: | 
 |   // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/sha3/sha-3bytetestvectors.zip | 
 |   const char kMsg[] = | 
 |       "\xa7\x48\x47\x93\x0a\x03\xab\xee\xa4\x73\xe1\xf3\xdc\x30" | 
 |       "\xb8\x88\x15"; | 
 |   const size_t kSize = ARRAYSIZE(kMsg); | 
 |   const uint32_t kExpect = 0x29f9a6db; | 
 |   const dif_kmac_mode_sha3_t kMode = kDifKmacModeSha3Len384; | 
 |   dif_kmac_operation_state_t operation_state; | 
 |  | 
 |   for (size_t i = 0; i < sizeof(uint32_t); ++i) { | 
 |     char buffer[ARRAYSIZE(kMsg) + sizeof(uint32_t)] = {0}; | 
 |     memcpy(&buffer[i], kMsg, kSize); | 
 |  | 
 |     CHECK_DIF_OK(dif_kmac_mode_sha3_start(kmac, &operation_state, kMode)); | 
 |     CHECK_DIF_OK( | 
 |         dif_kmac_absorb(kmac, &operation_state, &buffer[i], kSize, NULL)); | 
 |  | 
 |     // Checking the first 32-bits of the digest is sufficient. | 
 |     uint32_t out; | 
 |     CHECK_DIF_OK( | 
 |         dif_kmac_squeeze(kmac, &operation_state, &out, sizeof(uint32_t), NULL)); | 
 |     CHECK_DIF_OK(dif_kmac_end(kmac, &operation_state)); | 
 |  | 
 |     CHECK_DIF_OK((out == kExpect), | 
 |                  "mismatch at alignment %u got 0x%u want 0x%x", i, out, | 
 |                  kExpect); | 
 |   } | 
 |  | 
 |   // Run a SHA-3 test case using multiple absorb calls. | 
 |   { | 
 |     CHECK_DIF_OK(dif_kmac_mode_sha3_start(kmac, &operation_state, kMode)); | 
 |     CHECK_DIF_OK(dif_kmac_absorb(kmac, &operation_state, &kMsg[0], 1, NULL)); | 
 |     CHECK_DIF_OK(dif_kmac_absorb(kmac, &operation_state, &kMsg[1], 2, NULL)); | 
 |     CHECK_DIF_OK(dif_kmac_absorb(kmac, &operation_state, &kMsg[3], 5, NULL)); | 
 |     CHECK_DIF_OK(dif_kmac_absorb(kmac, &operation_state, &kMsg[8], 4, NULL)); | 
 |     CHECK_DIF_OK( | 
 |         dif_kmac_absorb(kmac, &operation_state, &kMsg[12], kSize - 12, NULL)); | 
 |  | 
 |     // Checking the first 32-bits of the digest is sufficient. | 
 |     uint32_t out; | 
 |     CHECK_DIF_OK( | 
 |         dif_kmac_squeeze(kmac, &operation_state, &out, sizeof(uint32_t), NULL)); | 
 |     CHECK_DIF_OK(dif_kmac_end(kmac, &operation_state)); | 
 |  | 
 |     CHECK_DIF_OK((out == kExpect), "mismatch got 0x%u want 0x%x", out, kExpect); | 
 |   } | 
 | } | 
 |  | 
 | /** | 
 |  * Run SHAKE test cases using single blocking absorb/squeeze operations. | 
 |  */ | 
 | void run_shake_test(dif_kmac_t *kmac) { | 
 |   dif_kmac_operation_state_t operation_state; | 
 |  | 
 |   for (int i = 0; i < ARRAYSIZE(shake_tests); ++i) { | 
 |     shake_test_t test = shake_tests[i]; | 
 |  | 
 |     CHECK_DIF_OK(dif_kmac_mode_shake_start(kmac, &operation_state, test.mode)); | 
 |     if (test.message_len > 0) { | 
 |       CHECK_DIF_OK(dif_kmac_absorb(kmac, &operation_state, test.message, | 
 |                                    test.message_len, NULL)); | 
 |     } | 
 |     uint32_t out[DIGEST_LEN_SHAKE_MAX]; | 
 |     CHECK(DIGEST_LEN_SHAKE_MAX >= test.digest_len); | 
 |     CHECK_DIF_OK( | 
 |         dif_kmac_squeeze(kmac, &operation_state, out, test.digest_len, NULL)); | 
 |     CHECK_DIF_OK(dif_kmac_end(kmac, &operation_state)); | 
 |  | 
 |     for (int j = 0; j < test.digest_len; ++j) { | 
 |       CHECK(out[j] == test.digest[j], | 
 |             "test %d: mismatch at %d got=0x%x want=0x%x", i, j, out[j], | 
 |             test.digest[j]); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | bool test_main(void) { | 
 |   LOG_INFO("Running KMAC DIF test..."); | 
 |  | 
 |   // Intialize KMAC hardware. | 
 |   dif_kmac_t kmac; | 
 |   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)); | 
 |  | 
 |   run_sha3_test(&kmac); | 
 |   run_sha3_alignment_test(&kmac); | 
 |   run_shake_test(&kmac); | 
 |  | 
 |   return true; | 
 | } |