text: // 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/macros.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"
  
  const test_config_t kTestConfig;
  
  #define DIGEST_LEN_KMAC_MAX 100
  
  /**
   * KMAC test description.
   */
  typedef struct kmac_test {
    dif_kmac_mode_kmac_t mode;
    dif_kmac_key_t key;
  
    const char *message;
    size_t message_len;
  
    const char *customization_string;
    size_t customization_string_len;
  
    const uint32_t digest[DIGEST_LEN_KMAC_MAX];
    size_t digest_len;
    bool digest_len_is_fixed;
  } kmac_test_t;
  
  /**
   * KMAC tests.
   *
   * KMAC examples taken from:
   * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMAC_samples.pdf
   *
   * KMACXOF examples taken from:
   * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMACXOF_samples.pdf
   */
  const kmac_test_t kmac_tests[] = {
      // KMAC
      {
          .mode = kDifKmacModeKmacLen128,
          .key =
              (dif_kmac_key_t){
                  .share0 = {0x43424140, 0x47464544, 0x4B4A4948, 0x4F4E4D4C,
                             0x53525150, 0x57565554, 0x5B5A5958, 0x5F5E5D5C},
                  .share1 = {0},
                  .length = kDifKmacKeyLen256,
              },
          .message = "\x00\x01\x02\x03",
          .message_len = 4,
          .customization_string = "",
          .customization_string_len = 0,
          .digest = {0x0D0B78E5, 0xD3F7A63E, 0x70C529A4, 0x003AA46A, 0xD4D7DBFA,
                     0x9E832896, 0x3F248731, 0x4EE16E45},
          .digest_len = 8,
          .digest_len_is_fixed = true,
      },
      {
          .mode = kDifKmacModeKmacLen256,
          .key =
              (dif_kmac_key_t){
                  .share0 = {0x43424140, 0x47464544, 0x4B4A4948, 0x4F4E4D4C,
                             0x53525150, 0x57565554, 0x5B5A5958, 0x5F5E5D5C},
                  .share1 = {0},
                  .length = kDifKmacKeyLen256,
              },
          .message =
              "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
              "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
              "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
              "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
              "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
              "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
              "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
              "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
              "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
              "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
              "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
              "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
              "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
          .message_len = 200,
          .customization_string = "My Tagged Application",
          .customization_string_len = 21,
          .digest = {0xF71886B5, 0xD5E1921F, 0x558C1B6C, 0x18CDD7DD, 0xCAB4978B,
                     0x1E83994D, 0x839A69B2, 0xD9E4A27D, 0xFDACFB70, 0xAE3300E5,
                     0xA2F185A5, 0xC3108570, 0x0888072D, 0x2818BD01, 0x6847FE98,
                     0x6589FC76},
          .digest_len = 16,
          .digest_len_is_fixed = true,
      },
      {
          .mode = kDifKmacModeKmacLen128,
          .key =
              (dif_kmac_key_t){
                  .share0 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
                             15},
                  .share1 = {0},
                  .length = kDifKmacKeyLen512,
              },
          .message = "OpenTitan",
          .message_len = 9,
          .customization_string =
              "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
              "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
          .customization_string_len = 32,
          .digest = {0x0A77209A, 0x81797CFC, 0x6C6A61AA, 0x87E02697, 0xFC583498,
                     0x924C7FD8, 0xD7E11A80, 0xCEBFD97E, 0x5D01E715, 0xE197129F,
                     0xCED75441, 0x3A08D021, 0xBBACB3CA, 0x353539F9, 0xCD225ACE,
                     0x07C377A5, 0xDEB816E7, 0x6102E338, 0xBA1BA63C, 0x9FD50F0E,
                     0x2B2F632E, 0xABC632E1, 0xF44E5360, 0x01618ABD, 0xCEA93A18,
                     0xA25E1479, 0xACE0387A, 0x8CC8E65A, 0xC5323FBD, 0xCE278A2F,
                     0x6E5C6CD4, 0xDEF0B252, 0xC9569830, 0xDCD1E15A, 0x01592E1D,
                     0x6D41FBEC, 0x7625B67E, 0x2E6FDC71, 0x753253F6, 0xCBE2EE7B,
                     0x94B3F8AB, 0x5F7B9F4B, 0x9C32B704, 0xB75D2CD2, 0x2B9BF8D5,
                     0xF0C43941, 0x070A972F, 0x29039D89, 0x985B43BE, 0x3739526F,
                     0xEB9DE9FE, 0xE885D4EB, 0x147B854A, 0xF39840A4, 0x927FCEEF,
                     0xAA41A128, 0xBF85C5C4, 0x492D7E2B, 0xC39FC808, 0x260A3D02,
                     0x0EAB74F2, 0xFE7B8A99, 0xF77C71F7, 0x49D69382, 0x7B8405D4,
                     0x3D55F0F9, 0x551EAD0B, 0x53D648D0, 0x1820BAEB, 0x8D94C965,
                     0x079BC208, 0xD4D2742F, 0x8496D429, 0x464B6D3A, 0x34899027,
                     0x940B6F55, 0x154F43FB, 0x8C39F574, 0x89E07C5F, 0xE10F713B,
                     0x8B638E35, 0x16F0BFCE, 0x21CB26F8, 0x0A25F977, 0xAD944F1B,
                     0x6B8A6DB7, 0x0ABD1C91, 0x18E2C5AF, 0xE9AF73F5, 0x79CD8C86,
                     0x6830AD6F, 0x9EA2CC45, 0xA70D1807, 0x38993A63, 0xC2BF657E,
                     0x7CE11825, 0x98774D38, 0x9DB867E7, 0xB5F8CBFB, 0x86B242D5},
          .digest_len = 100,
          .digest_len_is_fixed = true,
      },
      // KMACXOF
      {
          .mode = kDifKmacModeKmacLen128,
          .key =
              (dif_kmac_key_t){
                  .share0 = {0x43424140, 0x47464544, 0x4B4A4948, 0x4F4E4D4C,
                             0x53525150, 0x57565554, 0x5B5A5958, 0x5F5E5D5C},
                  .share1 = {0},
                  .length = kDifKmacKeyLen256,
              },
          .message = "\x00\x01\x02\x03",
          .message_len = 4,
          .customization_string = "",
          .customization_string_len = 0,
          .digest = {0x0B7483CD, 0xC8CC92BD, 0x142B03CF, 0x46F4A081, 0xDDA97C0E,
                     0x0C8AB012, 0x8B173140, 0x35ECD6AC},
          .digest_len = 8,
          .digest_len_is_fixed = false,
      },
      {
          .mode = kDifKmacModeKmacLen256,
          .key =
              (dif_kmac_key_t){
                  .share0 = {0x43424140, 0x47464544, 0x4B4A4948, 0x4F4E4D4C,
                             0x53525150, 0x57565554, 0x5B5A5958, 0x5F5E5D5C},
                  .share1 = {0},
                  .length = kDifKmacKeyLen256,
              },
          .message =
              "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
              "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
              "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
              "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
              "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
              "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
              "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
              "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
              "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
              "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
              "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
              "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
              "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
          .message_len = 200,
          .customization_string = "My Tagged Application",
          .customization_string_len = 21,
          .digest = {0x1C73BED5, 0x73D74E95, 0x59BB4628, 0xE3A8E3DB, 0x7AE7830F,
                     0x5944FF4B, 0xB4C2F1F2, 0xCEB8EBEC, 0xC601BA67, 0x57B88A2E,
                     0x9B492D8D, 0x6727BBD1, 0x90117868, 0x6A300A02, 0x1D28DE97,
                     0x5D3030CC},
          .digest_len = 16,
          .digest_len_is_fixed = false,
      },
  };
  
  bool test_main() {
    LOG_INFO("Running KMAC DIF test...");
  
    // Intialize KMAC hardware.
    dif_kmac_t kmac;
    dif_kmac_operation_state_t kmac_operation_state;
    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 fixed length KMAC test cases using single blocking absorb/squeeze
    // operations.
    for (int i = 0; i < ARRAYSIZE(kmac_tests); ++i) {
      kmac_test_t test = kmac_tests[i];
  
      dif_kmac_customization_string_t s;
      CHECK_DIF_OK(dif_kmac_customization_string_init(
          test.customization_string, test.customization_string_len, &s));
  
      // Use NULL for empty strings to exercise that code path.
      dif_kmac_customization_string_t *sp =
          test.customization_string_len == 0 ? NULL : &s;
  
      size_t l = test.digest_len_is_fixed ? test.digest_len : 0;
      CHECK_DIF_OK(dif_kmac_mode_kmac_start(&kmac, &kmac_operation_state,
                                            test.mode, l, &test.key, sp));
      CHECK_DIF_OK(dif_kmac_absorb(&kmac, &kmac_operation_state, test.message,
                                   test.message_len, NULL));
      uint32_t out[DIGEST_LEN_KMAC_MAX];
      CHECK(DIGEST_LEN_KMAC_MAX >= test.digest_len);
      CHECK_DIF_OK(dif_kmac_squeeze(&kmac, &kmac_operation_state, out,
                                    test.digest_len, NULL));
      CHECK_DIF_OK(dif_kmac_end(&kmac, &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]);
      }
    }
  
    return true;
  }
  