|  | // 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/dif/dif_kmac.h" | 
|  |  | 
|  | #include <array> | 
|  | #include <cstring> | 
|  | #include <limits> | 
|  | #include <ostream> | 
|  | #include <string> | 
|  |  | 
|  | #include "gmock/gmock.h" | 
|  | #include "gtest/gtest.h" | 
|  | #include "sw/device/lib/base/mmio.h" | 
|  | #include "sw/device/lib/base/mock_mmio.h" | 
|  | #include "sw/device/lib/dif/dif_test_base.h" | 
|  |  | 
|  | #include "kmac_regs.h"  // Generated | 
|  |  | 
|  | // We define global namespace == and << to make `dif_i2c_timing_params_t` work | 
|  | // nicely with EXPECT_EQ. | 
|  | bool operator==(dif_kmac_operation_state_t a, dif_kmac_operation_state_t b) { | 
|  | return a.squeezing == b.squeezing && a.append_d == b.append_d && | 
|  | a.offset == b.offset && a.r == b.r && a.d == b.d; | 
|  | } | 
|  |  | 
|  | std::ostream &operator<<(std::ostream &os, | 
|  | const dif_kmac_operation_state_t ¶ms) { | 
|  | return os << "{\n" | 
|  | << "  .squeezing = " << params.squeezing << ",\n" | 
|  | << "  .append_d = " << params.append_d << ",\n" | 
|  | << "  .offset = " << params.offset << ",\n" | 
|  | << "  .r = " << params.r << ",\n" | 
|  | << "  .d = " << params.d << ",\n" | 
|  | << "}"; | 
|  | } | 
|  |  | 
|  | namespace dif_kmac_unittest { | 
|  |  | 
|  | using ::testing::ElementsAre; | 
|  | using testing::ElementsAreArray; | 
|  |  | 
|  | TEST(CustomizationStringTest, Encode) { | 
|  | dif_kmac_customization_string_t cs; | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_customization_string_init(nullptr, 0, &cs)); | 
|  | EXPECT_THAT(std::string(&cs.buffer[0], 2), ElementsAre(1, 0)); | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_customization_string_init("", 0, &cs)); | 
|  | EXPECT_THAT(std::string(&cs.buffer[0], 2), ElementsAre(1, 0)); | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_customization_string_init("\x00\x00", 2, &cs)); | 
|  | EXPECT_THAT(std::string(&cs.buffer[0], 2), ElementsAre(1, 16)); | 
|  | EXPECT_THAT(std::string(&cs.buffer[2], 2), ElementsAre(0, 0)); | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_customization_string_init("SHA-3", 5, &cs)); | 
|  | EXPECT_THAT(std::string(&cs.buffer[0], 2), ElementsAre(1, 40)); | 
|  | EXPECT_EQ(std::string(&cs.buffer[2], 5), "SHA-3"); | 
|  |  | 
|  | std::string max(kDifKmacMaxCustomizationStringLen, 0x12); | 
|  | EXPECT_DIF_OK( | 
|  | dif_kmac_customization_string_init(max.data(), max.size(), &cs)); | 
|  | static_assert(kDifKmacMaxCustomizationStringLen == 32, | 
|  | "encoding needs to be updated"); | 
|  | EXPECT_THAT(std::string(&cs.buffer[0], 3), ElementsAre(2, 1, 0)); | 
|  | EXPECT_EQ(std::string(&cs.buffer[3], max.size()), max); | 
|  | } | 
|  |  | 
|  | TEST(CustomizationStringTest, BadArg) { | 
|  | EXPECT_DIF_BADARG(dif_kmac_customization_string_init("", 0, nullptr)); | 
|  |  | 
|  | dif_kmac_customization_string_t cs; | 
|  | EXPECT_DIF_BADARG(dif_kmac_customization_string_init(nullptr, 1, &cs)); | 
|  | EXPECT_DIF_BADARG(dif_kmac_customization_string_init( | 
|  | "", kDifKmacMaxCustomizationStringLen + 1, &cs)); | 
|  | EXPECT_DIF_BADARG(dif_kmac_customization_string_init("", -1, &cs)); | 
|  | } | 
|  |  | 
|  | TEST(FunctionNameTest, Encode) { | 
|  | dif_kmac_function_name_t fn; | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_function_name_init(nullptr, 0, &fn)); | 
|  | EXPECT_THAT(std::string(&fn.buffer[0], 2), ElementsAre(1, 0)); | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_function_name_init("", 0, &fn)); | 
|  | EXPECT_THAT(std::string(&fn.buffer[0], 2), ElementsAre(1, 0)); | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_function_name_init("\x00\x00", 2, &fn)); | 
|  | EXPECT_THAT(std::string(&fn.buffer[0], 2), ElementsAre(1, 16)); | 
|  | EXPECT_THAT(std::string(&fn.buffer[2], 2), ElementsAre(0, 0)); | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_function_name_init("KMAC", 4, &fn)); | 
|  | EXPECT_THAT(std::string(&fn.buffer[0], 2), ElementsAre(1, 32)); | 
|  | EXPECT_EQ(std::string(&fn.buffer[2], 4), "KMAC"); | 
|  |  | 
|  | std::string max(kDifKmacMaxFunctionNameLen, 0x34); | 
|  | EXPECT_DIF_OK(dif_kmac_function_name_init(max.data(), max.size(), &fn)); | 
|  | static_assert(kDifKmacMaxFunctionNameLen == 4, | 
|  | "encoding needs to be updated"); | 
|  | EXPECT_THAT(std::string(&fn.buffer[0], 2), ElementsAre(1, 32)); | 
|  | EXPECT_EQ(std::string(&fn.buffer[2], max.size()), max); | 
|  | } | 
|  |  | 
|  | TEST(FunctionNameTest, BadArg) { | 
|  | EXPECT_DIF_BADARG(dif_kmac_function_name_init("", 0, nullptr)); | 
|  |  | 
|  | dif_kmac_function_name_t fn; | 
|  | EXPECT_DIF_BADARG(dif_kmac_function_name_init(nullptr, 1, &fn)); | 
|  | EXPECT_DIF_BADARG( | 
|  | dif_kmac_function_name_init("", kDifKmacMaxFunctionNameLen + 1, &fn)); | 
|  | EXPECT_DIF_BADARG(dif_kmac_function_name_init("", -1, &fn)); | 
|  | } | 
|  |  | 
|  | using mock_mmio::MmioTest; | 
|  | using mock_mmio::MockDevice; | 
|  | using testing::Test; | 
|  |  | 
|  | // Base class for the rest fixtures in this file. | 
|  | class KmacTest : public testing::Test, public mock_mmio::MmioTest { | 
|  | protected: | 
|  | dif_kmac_t kmac_; | 
|  | dif_kmac_operation_state_t op_state_ = { | 
|  | .squeezing = false, | 
|  | .append_d = false, | 
|  | .offset = 0, | 
|  | .r = 0, | 
|  | .d = 0, | 
|  | }; | 
|  |  | 
|  | static constexpr std::array<uint8_t, 17> kMsg = { | 
|  | 0xa7, 0x48, 0x47, 0x93, 0x0a, 0x03, 0xab, 0xee, 0xa4, | 
|  | 0x73, 0xe1, 0xf3, 0xdc, 0x30, 0xb8, 0x88, 0x15}; | 
|  |  | 
|  | struct ConfigRegister { | 
|  | bool enable = false; | 
|  | uint8_t key_strength = KMAC_CFG_SHADOWED_KSTRENGTH_VALUE_L256; | 
|  | uint8_t mode = KMAC_CFG_SHADOWED_MODE_VALUE_CSHAKE; | 
|  | bool msg_big_endian = false; | 
|  | bool state_big_endian = false; | 
|  | bool sideload = false; | 
|  | uint8_t entropy_mode = KMAC_CFG_SHADOWED_ENTROPY_MODE_VALUE_IDLE_MODE; | 
|  | bool entropy_fast_process = false; | 
|  | bool msg_mask = false; | 
|  | bool entropy_ready = false; | 
|  | bool err_processed = false; | 
|  | bool enable_unsupported_mode_strength = false; | 
|  | uint16_t entropy_hash_threshold = 0; | 
|  | uint16_t entropy_wait_timer = 0; | 
|  | uint16_t entropy_prescaler = 0; | 
|  | } config_reg_; | 
|  |  | 
|  | KmacTest() { EXPECT_DIF_OK(dif_kmac_init(dev().region(), &kmac_)); } | 
|  |  | 
|  | /** | 
|  | * Set mmio write expectation for 8 bits data size. | 
|  | * | 
|  | * @param message Buffer with the data. | 
|  | * @param size Len of the buffer. | 
|  | */ | 
|  | void ExpectMessageByte(const uint8_t *message, const size_t size) { | 
|  | for (size_t i = 0; i < size; ++i) { | 
|  | EXPECT_WRITE8(KMAC_MSG_FIFO_REG_OFFSET, message[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Set mmio write expectation for 32 bits data size considering an alignment | 
|  | * of 32 bits. | 
|  | * | 
|  | * @param message Buffer with the data. | 
|  | * @param size Len of the buffer. | 
|  | */ | 
|  | void ExpectMessageInt32(const uint8_t *message, const size_t size) { | 
|  | // Check if the buffer is unaligned. | 
|  | size_t remaining = size; | 
|  | size_t unalignment = ((uintptr_t)message) % sizeof(uint32_t); | 
|  | if (unalignment) { | 
|  | // write unaligned data in bytes. | 
|  | unalignment = sizeof(uint32_t) - unalignment; | 
|  | ExpectMessageByte(message, unalignment); | 
|  | message += unalignment; | 
|  | remaining -= unalignment; | 
|  | } | 
|  |  | 
|  | // Write aligned part of the buffer. | 
|  | while (remaining >= sizeof(uint32_t)) { | 
|  | uint32_t word = 0; | 
|  | memcpy(&word, message, sizeof(uint32_t)); | 
|  | EXPECT_WRITE32(KMAC_MSG_FIFO_REG_OFFSET, word); | 
|  | remaining -= sizeof(uint32_t); | 
|  | message += sizeof(uint32_t); | 
|  | } | 
|  | // Check if there still unaligned data in the buffer tail. | 
|  | if (remaining) { | 
|  | // write unaligned data in bytes. | 
|  | ExpectMessageByte(message, remaining); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ExpectConfig(void) { | 
|  | EXPECT_WRITE32_SHADOWED( | 
|  | KMAC_CFG_SHADOWED_REG_OFFSET, | 
|  | {{KMAC_CFG_SHADOWED_KMAC_EN_BIT, config_reg_.enable}, | 
|  | {KMAC_CFG_SHADOWED_KSTRENGTH_OFFSET, config_reg_.key_strength}, | 
|  | {KMAC_CFG_SHADOWED_MODE_OFFSET, config_reg_.mode}, | 
|  | {KMAC_CFG_SHADOWED_MSG_ENDIANNESS_BIT, config_reg_.msg_big_endian}, | 
|  | {KMAC_CFG_SHADOWED_STATE_ENDIANNESS_BIT, config_reg_.state_big_endian}, | 
|  | {KMAC_CFG_SHADOWED_SIDELOAD_BIT, config_reg_.sideload}, | 
|  | {KMAC_CFG_SHADOWED_ENTROPY_MODE_OFFSET, config_reg_.entropy_mode}, | 
|  | {KMAC_CFG_SHADOWED_ENTROPY_FAST_PROCESS_BIT, | 
|  | config_reg_.entropy_fast_process}, | 
|  | {KMAC_CFG_SHADOWED_MSG_MASK_BIT, config_reg_.msg_mask}, | 
|  | {KMAC_CFG_SHADOWED_ENTROPY_READY_BIT, config_reg_.entropy_ready}, | 
|  | {KMAC_CFG_SHADOWED_ERR_PROCESSED_BIT, config_reg_.err_processed}, | 
|  | {KMAC_CFG_SHADOWED_EN_UNSUPPORTED_MODESTRENGTH_BIT, | 
|  | config_reg_.enable_unsupported_mode_strength}}); | 
|  | } | 
|  |  | 
|  | void ExpectKey(const dif_kmac_key_t &key) { | 
|  | std::map<dif_kmac_key_length_t, uint32_t> key_size_map = { | 
|  | {kDifKmacKeyLen128, KMAC_KEY_LEN_LEN_VALUE_KEY128}, | 
|  | {kDifKmacKeyLen192, KMAC_KEY_LEN_LEN_VALUE_KEY192}, | 
|  | {kDifKmacKeyLen256, KMAC_KEY_LEN_LEN_VALUE_KEY256}, | 
|  | {kDifKmacKeyLen384, KMAC_KEY_LEN_LEN_VALUE_KEY384}, | 
|  | {kDifKmacKeyLen512, KMAC_KEY_LEN_LEN_VALUE_KEY512}, | 
|  | }; | 
|  |  | 
|  | EXPECT_WRITE32(KMAC_KEY_LEN_REG_OFFSET, key_size_map[key.length]); | 
|  | for (uint32_t i = 0; i < ARRAYSIZE(key.share0); ++i) { | 
|  | ptrdiff_t offset = KMAC_KEY_SHARE0_0_REG_OFFSET + (i * sizeof(uint32_t)); | 
|  | EXPECT_WRITE32(offset, key.share0[i]); | 
|  | offset = KMAC_KEY_SHARE1_0_REG_OFFSET + (i * sizeof(uint32_t)); | 
|  | EXPECT_WRITE32(offset, key.share1[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ExpectPrefix(const uint32_t *prefix_regs, uint32_t size) { | 
|  | for (uint32_t i = 0; i < size; ++i) { | 
|  | ptrdiff_t offset = KMAC_PREFIX_0_REG_OFFSET + i * sizeof(uint32_t); | 
|  | EXPECT_WRITE32(offset, prefix_regs[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ExpectEntropySeed(const uint32_t *seed) { | 
|  | for (uint32_t i = 0; i < kDifKmacEntropySeedWords; ++i) { | 
|  | ptrdiff_t offset = KMAC_ENTROPY_SEED_0_REG_OFFSET + i * sizeof(uint32_t); | 
|  | EXPECT_WRITE32(offset, seed[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | uint32_t GetRateBits(uint32_t security_level) { | 
|  | // Formula for the rate in bits is: | 
|  | // | 
|  | //   r = 1600 - c | 
|  | // | 
|  | // Where c is the capacity (the security level in bits multiplied by two). | 
|  | return 1600 - 2 * security_level; | 
|  | } | 
|  |  | 
|  | uint32_t GetRateWords(uint32_t security_level) { | 
|  | return GetRateBits(security_level) / 32; | 
|  | } | 
|  | }; | 
|  |  | 
|  | class Kmac256Test : public KmacTest { | 
|  | protected: | 
|  | dif_kmac_key_t key_ = { | 
|  | .share0 = {0x43424140, 0x47464544, 0x4B4A4948, 0x4F4E4D4C, 0x53525150, | 
|  | 0x57565554, 0x5B5A5958, 0x5F5E5D5C}, | 
|  | .share1 = {0}, | 
|  | .length = kDifKmacKeyLen256, | 
|  | }; | 
|  | dif_kmac_mode_kmac_t mode_ = kDifKmacModeKmacLen256; | 
|  | dif_kmac_customization_string_t custom_string_; | 
|  |  | 
|  | Kmac256Test() { | 
|  | const std::string string = "My Tagged Application"; | 
|  | EXPECT_DIF_OK(dif_kmac_customization_string_init( | 
|  | string.c_str(), string.size(), &custom_string_)); | 
|  | config_reg_.enable = true; | 
|  | config_reg_.mode = KMAC_CFG_SHADOWED_MODE_VALUE_CSHAKE; | 
|  | } | 
|  |  | 
|  | void ExpectPrefix(const dif_kmac_customization_string_t &s) { | 
|  | // Initialize prefix registers with function name ("KMAC") and empty | 
|  | // customization string. The empty customization string will be overwritten | 
|  | // if a non-empty string is provided. | 
|  | std::string prefix_str("\001 KMAC\001"); | 
|  |  | 
|  | // Encoded customization string (s) must be at least 3 bytes long if it is | 
|  | // not the empty string. | 
|  | if (s.length >= 3) { | 
|  | // First two bytes overwrite the pre-encoded empty customization string. | 
|  | prefix_str[prefix_str.size() - 1] |= s.buffer[0] & 0xFF; | 
|  | prefix_str.push_back(s.buffer[1] & 0xFF); | 
|  | prefix_str.insert(prefix_str.end(), &s.buffer[2], &s.buffer[s.length]); | 
|  | } | 
|  |  | 
|  | std::vector<uint32_t> prefix_regs(11, 0); | 
|  | memcpy(prefix_regs.data(), prefix_str.data(), prefix_str.size()); | 
|  | KmacTest::ExpectPrefix(prefix_regs.data(), prefix_regs.size()); | 
|  | } | 
|  | }; | 
|  |  | 
|  | TEST_F(Kmac256Test, StartSuccess) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_IDLE_BIT, true}}); | 
|  | ExpectKey(key_); | 
|  | EXPECT_READ32(KMAC_CFG_SHADOWED_REG_OFFSET, 0); | 
|  | ExpectConfig(); | 
|  | ExpectPrefix(custom_string_); | 
|  | EXPECT_WRITE32(KMAC_CMD_REG_OFFSET, | 
|  | {{KMAC_CMD_CMD_OFFSET, KMAC_CMD_CMD_VALUE_START}}); | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_ABSORB_BIT, true}}); | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_mode_kmac_start(&kmac_, &op_state_, mode_, 0, &key_, | 
|  | &custom_string_)); | 
|  | EXPECT_EQ(op_state_.squeezing, false); | 
|  | EXPECT_EQ(op_state_.append_d, true); | 
|  | EXPECT_EQ(op_state_.offset, 0); | 
|  | EXPECT_EQ(op_state_.r, GetRateWords(256)); | 
|  | EXPECT_EQ(op_state_.d, 0); | 
|  | } | 
|  |  | 
|  | TEST_F(Kmac256Test, StartBadArg) { | 
|  | EXPECT_DIF_BADARG(dif_kmac_mode_kmac_start(nullptr, &op_state_, mode_, 0, | 
|  | &key_, &custom_string_)); | 
|  |  | 
|  | EXPECT_DIF_BADARG(dif_kmac_mode_kmac_start(&kmac_, nullptr, mode_, 0, &key_, | 
|  | &custom_string_)); | 
|  |  | 
|  | EXPECT_DIF_BADARG(dif_kmac_mode_kmac_start(&kmac_, &op_state_, mode_, | 
|  | kDifKmacMaxOutputLenWords + 1, | 
|  | &key_, &custom_string_)); | 
|  |  | 
|  | EXPECT_DIF_BADARG(dif_kmac_mode_kmac_start(&kmac_, &op_state_, | 
|  | (dif_kmac_mode_kmac_t)0xff, 0, | 
|  | &key_, &custom_string_)); | 
|  |  | 
|  | EXPECT_DIF_BADARG(dif_kmac_mode_kmac_start(&kmac_, &op_state_, mode_, 0, | 
|  | nullptr, &custom_string_)); | 
|  |  | 
|  | key_.length = static_cast<dif_kmac_key_length_t>(0xFF); | 
|  | EXPECT_DIF_BADARG(dif_kmac_mode_kmac_start(&kmac_, &op_state_, mode_, 0, | 
|  | &key_, &custom_string_)); | 
|  | } | 
|  |  | 
|  | TEST_F(Kmac256Test, StartError) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_IDLE_BIT, false}}); | 
|  | EXPECT_EQ(dif_kmac_mode_kmac_start(&kmac_, &op_state_, mode_, 0, &key_, | 
|  | &custom_string_), | 
|  | kDifError); | 
|  | } | 
|  |  | 
|  | class Sha3_224Test : public KmacTest { | 
|  | protected: | 
|  | dif_kmac_mode_sha3_t mode_ = kDifKmacModeSha3Len224; | 
|  |  | 
|  | Sha3_224Test() { | 
|  | config_reg_.mode = KMAC_CFG_SHADOWED_MODE_VALUE_SHA3; | 
|  | config_reg_.key_strength = KMAC_CFG_SHADOWED_KSTRENGTH_VALUE_L224; | 
|  | } | 
|  | }; | 
|  |  | 
|  | TEST_F(Sha3_224Test, StartSuccess) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_IDLE_BIT, true}}); | 
|  | EXPECT_READ32(KMAC_CFG_SHADOWED_REG_OFFSET, | 
|  | {{KMAC_CFG_SHADOWED_KMAC_EN_BIT, false}}); | 
|  | ExpectConfig(); | 
|  | EXPECT_WRITE32(KMAC_CMD_REG_OFFSET, | 
|  | {{KMAC_CMD_CMD_OFFSET, KMAC_CMD_CMD_VALUE_START}}); | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_ABSORB_BIT, true}}); | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_mode_sha3_start(&kmac_, &op_state_, mode_)); | 
|  | } | 
|  |  | 
|  | TEST_F(Sha3_224Test, StartBadArg) { | 
|  | EXPECT_DIF_BADARG(dif_kmac_mode_sha3_start(nullptr, &op_state_, mode_)); | 
|  |  | 
|  | EXPECT_DIF_BADARG(dif_kmac_mode_sha3_start(&kmac_, nullptr, mode_)); | 
|  |  | 
|  | EXPECT_DIF_BADARG( | 
|  | dif_kmac_mode_sha3_start(&kmac_, &op_state_, (dif_kmac_mode_sha3_t)0xff)); | 
|  | } | 
|  |  | 
|  | TEST_F(Sha3_224Test, StartError) { | 
|  | { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_IDLE_BIT, false}}); | 
|  | EXPECT_EQ(dif_kmac_mode_sha3_start(&kmac_, &op_state_, mode_), kDifError); | 
|  | } | 
|  | } | 
|  |  | 
|  | class Shake128Test : public KmacTest { | 
|  | protected: | 
|  | dif_kmac_mode_shake_t mode_ = kDifKmacModeShakeLen128; | 
|  |  | 
|  | Shake128Test() { | 
|  | config_reg_.mode = KMAC_CFG_SHADOWED_MODE_VALUE_SHAKE; | 
|  | config_reg_.key_strength = KMAC_CFG_SHADOWED_KSTRENGTH_VALUE_L128; | 
|  | } | 
|  | }; | 
|  |  | 
|  | TEST_F(Shake128Test, StartSuccess) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_IDLE_BIT, true}}); | 
|  | EXPECT_READ32(KMAC_CFG_SHADOWED_REG_OFFSET, | 
|  | {{KMAC_CFG_SHADOWED_KMAC_EN_BIT, false}}); | 
|  | ExpectConfig(); | 
|  | EXPECT_WRITE32(KMAC_CMD_REG_OFFSET, | 
|  | {{KMAC_CMD_CMD_OFFSET, KMAC_CMD_CMD_VALUE_START}}); | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_ABSORB_BIT, true}}); | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_mode_shake_start(&kmac_, &op_state_, mode_)); | 
|  | } | 
|  |  | 
|  | TEST_F(Shake128Test, StartBadArg) { | 
|  | EXPECT_DIF_BADARG(dif_kmac_mode_shake_start(nullptr, &op_state_, mode_)); | 
|  |  | 
|  | EXPECT_DIF_BADARG(dif_kmac_mode_shake_start(&kmac_, nullptr, mode_)); | 
|  |  | 
|  | EXPECT_DIF_BADARG(dif_kmac_mode_shake_start(&kmac_, &op_state_, | 
|  | (dif_kmac_mode_shake_t)0xff)); | 
|  | } | 
|  |  | 
|  | TEST_F(Shake128Test, StartError) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_IDLE_BIT, false}}); | 
|  | EXPECT_EQ(dif_kmac_mode_shake_start(&kmac_, &op_state_, mode_), kDifError); | 
|  | } | 
|  |  | 
|  | class Cshake256Test : public KmacTest { | 
|  | protected: | 
|  | dif_kmac_mode_cshake_t mode_ = kDifKmacModeCshakeLen256; | 
|  | dif_kmac_customization_string_t custom_str_; | 
|  | dif_kmac_function_name_t func_name_; | 
|  |  | 
|  | Cshake256Test() { | 
|  | const std::string string = "My Application"; | 
|  | EXPECT_DIF_OK(dif_kmac_customization_string_init( | 
|  | string.c_str(), string.size(), &custom_str_)); | 
|  |  | 
|  | const std::string kFunctionName = "Foo"; | 
|  | EXPECT_DIF_OK(dif_kmac_function_name_init( | 
|  | kFunctionName.c_str(), kFunctionName.size(), &func_name_)); | 
|  |  | 
|  | config_reg_.mode = KMAC_CFG_SHADOWED_MODE_VALUE_CSHAKE; | 
|  | config_reg_.key_strength = KMAC_CFG_SHADOWED_KSTRENGTH_VALUE_L256; | 
|  | } | 
|  |  | 
|  | void ExpectPrefix(const dif_kmac_customization_string_t &s) { | 
|  | // Calculate PREFIX register values. | 
|  | std::vector<uint8_t> prefixData; | 
|  | if (func_name_.length == 0) { | 
|  | // Append left encoded empty string. | 
|  | prefixData.push_back(1); | 
|  | prefixData.push_back(0); | 
|  | } else { | 
|  | prefixData.insert(prefixData.end(), func_name_.buffer, | 
|  | func_name_.buffer + func_name_.length); | 
|  | } | 
|  |  | 
|  | if (s.length == 0) { | 
|  | // Append left encoded empty string. | 
|  | prefixData.push_back(1); | 
|  | prefixData.push_back(0); | 
|  | } else { | 
|  | prefixData.insert(prefixData.end(), s.buffer, s.buffer + s.length); | 
|  | } | 
|  |  | 
|  | std::vector<uint32_t> prefixRegs(11, 0); | 
|  | memcpy(prefixRegs.data(), prefixData.data(), prefixData.size()); | 
|  | KmacTest::ExpectPrefix(prefixRegs.data(), prefixRegs.size()); | 
|  | } | 
|  |  | 
|  | void CheckOperationState(dif_kmac_operation_state_t &operation_state) { | 
|  | EXPECT_EQ(op_state_.squeezing, false); | 
|  | EXPECT_EQ(op_state_.append_d, false); | 
|  | EXPECT_EQ(op_state_.offset, 0); | 
|  | EXPECT_EQ(op_state_.d, 0); | 
|  | EXPECT_EQ(op_state_.r, GetRateWords(256)); | 
|  | } | 
|  | }; | 
|  |  | 
|  | TEST_F(Cshake256Test, StartAllArgsSuccess) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_IDLE_BIT, true}}); | 
|  | EXPECT_READ32(KMAC_CFG_SHADOWED_REG_OFFSET, | 
|  | {{KMAC_CFG_SHADOWED_KMAC_EN_BIT, false}}); | 
|  | ExpectConfig(); | 
|  | ExpectPrefix(custom_str_); | 
|  | EXPECT_WRITE32(KMAC_CMD_REG_OFFSET, | 
|  | {{KMAC_CMD_CMD_OFFSET, KMAC_CMD_CMD_VALUE_START}}); | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_ABSORB_BIT, true}}); | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_mode_cshake_start(&kmac_, &op_state_, mode_, | 
|  | &func_name_, &custom_str_)); | 
|  | CheckOperationState(op_state_); | 
|  | } | 
|  |  | 
|  | TEST_F(Cshake256Test, StartNoFuncNameSuccess) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_IDLE_BIT, true}}); | 
|  | EXPECT_READ32(KMAC_CFG_SHADOWED_REG_OFFSET, | 
|  | {{KMAC_CFG_SHADOWED_KMAC_EN_BIT, false}}); | 
|  | ExpectConfig(); | 
|  | func_name_.length = 0; | 
|  | ExpectPrefix(custom_str_); | 
|  | EXPECT_WRITE32(KMAC_CMD_REG_OFFSET, | 
|  | {{KMAC_CMD_CMD_OFFSET, KMAC_CMD_CMD_VALUE_START}}); | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_ABSORB_BIT, true}}); | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_mode_cshake_start(&kmac_, &op_state_, mode_, nullptr, | 
|  | &custom_str_)); | 
|  | CheckOperationState(op_state_); | 
|  | } | 
|  |  | 
|  | TEST_F(Cshake256Test, StartNoCustomStrSuccess) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_IDLE_BIT, true}}); | 
|  | EXPECT_READ32(KMAC_CFG_SHADOWED_REG_OFFSET, | 
|  | {{KMAC_CFG_SHADOWED_KMAC_EN_BIT, false}}); | 
|  | ExpectConfig(); | 
|  | custom_str_.length = 0; | 
|  | ExpectPrefix(custom_str_); | 
|  | EXPECT_WRITE32(KMAC_CMD_REG_OFFSET, | 
|  | {{KMAC_CMD_CMD_OFFSET, KMAC_CMD_CMD_VALUE_START}}); | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_ABSORB_BIT, true}}); | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_mode_cshake_start(&kmac_, &op_state_, mode_, | 
|  | &func_name_, nullptr)); | 
|  | CheckOperationState(op_state_); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * In case the Function name and the Custom string are both empty the | 
|  | * `dif_kmac_mode_cshake_start` will fallback to `dif_kmac_mode_shake_start`. | 
|  | */ | 
|  | TEST_F(Cshake256Test, StartFallbackToShakeSuccess) { | 
|  | config_reg_.mode = KMAC_CFG_SHADOWED_MODE_VALUE_SHAKE; | 
|  |  | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_IDLE_BIT, true}}); | 
|  | EXPECT_READ32(KMAC_CFG_SHADOWED_REG_OFFSET, | 
|  | {{KMAC_CFG_SHADOWED_KMAC_EN_BIT, false}}); | 
|  | ExpectConfig(); | 
|  | EXPECT_WRITE32(KMAC_CMD_REG_OFFSET, | 
|  | {{KMAC_CMD_CMD_OFFSET, KMAC_CMD_CMD_VALUE_START}}); | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_ABSORB_BIT, true}}); | 
|  | EXPECT_DIF_OK( | 
|  | dif_kmac_mode_cshake_start(&kmac_, &op_state_, mode_, nullptr, nullptr)); | 
|  | } | 
|  |  | 
|  | TEST_F(Cshake256Test, StartBadArg) { | 
|  | EXPECT_DIF_BADARG(dif_kmac_mode_cshake_start(nullptr, &op_state_, mode_, | 
|  | &func_name_, &custom_str_)); | 
|  |  | 
|  | EXPECT_DIF_BADARG(dif_kmac_mode_cshake_start(&kmac_, nullptr, mode_, | 
|  | &func_name_, &custom_str_)); | 
|  |  | 
|  | EXPECT_DIF_BADARG(dif_kmac_mode_cshake_start(&kmac_, &op_state_, | 
|  | (dif_kmac_mode_cshake_t)0xff, | 
|  | &func_name_, &custom_str_)); | 
|  |  | 
|  | EXPECT_DIF_BADARG(dif_kmac_mode_cshake_start( | 
|  | &kmac_, &op_state_, (dif_kmac_mode_cshake_t)0xff, nullptr, nullptr)); | 
|  | } | 
|  |  | 
|  | TEST_F(Cshake256Test, StartError) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_IDLE_BIT, false}}); | 
|  | EXPECT_EQ(dif_kmac_mode_cshake_start(&kmac_, &op_state_, mode_, &func_name_, | 
|  | &custom_str_), | 
|  | kDifError); | 
|  | } | 
|  |  | 
|  | constexpr std::array<uint8_t, 17> KmacTest::kMsg; | 
|  |  | 
|  | class AbsorbalignmentMessage : public KmacTest { | 
|  | protected: | 
|  | AbsorbalignmentMessage() { op_state_.r = GetRateWords(256); } | 
|  | }; | 
|  |  | 
|  | TEST_F(AbsorbalignmentMessage, Success) { | 
|  | // Test assumption: message fits in the FIFO. | 
|  | static_assert(kMsg.size() <= KMAC_PARAM_NUM_ENTRIES_MSG_FIFO * | 
|  | KMAC_PARAM_NUM_BYTES_MSG_FIFO_ENTRY, | 
|  | "Message must fit in the KMAC message FIFO."); | 
|  |  | 
|  | uint8_t buffer[kMsg.size() + sizeof(uint32_t)]; | 
|  |  | 
|  | for (size_t i = 0; i < sizeof(uint32_t); i++) { | 
|  | uint8_t *pMsg = &buffer[i]; | 
|  | std::copy(kMsg.begin(), kMsg.end(), pMsg); | 
|  |  | 
|  | // First status read: checks for absorb bit. | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, 1 << KMAC_STATUS_SHA3_ABSORB_BIT); | 
|  |  | 
|  | // Second status read: checks FIFO depth. Always return 0 (i.e. 0 entries | 
|  | // occupied, FIFO is completely free). | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, 1 << KMAC_STATUS_SHA3_ABSORB_BIT); | 
|  | ExpectMessageInt32(pMsg, kMsg.size()); | 
|  |  | 
|  | EXPECT_DIF_OK( | 
|  | dif_kmac_absorb(&kmac_, &op_state_, pMsg, kMsg.size(), nullptr)); | 
|  | } | 
|  | } | 
|  |  | 
|  | class ConfigLock : public KmacTest {}; | 
|  |  | 
|  | TEST_F(ConfigLock, Locked) { | 
|  | EXPECT_READ32(KMAC_CFG_REGWEN_REG_OFFSET, 0); | 
|  |  | 
|  | bool lock = false; | 
|  | EXPECT_EQ(dif_kmac_config_is_locked(&kmac_, &lock), kDifOk); | 
|  | EXPECT_TRUE(lock); | 
|  | } | 
|  |  | 
|  | TEST_F(ConfigLock, Unlocked) { | 
|  | EXPECT_READ32(KMAC_CFG_REGWEN_REG_OFFSET, 1); | 
|  |  | 
|  | bool lock = true; | 
|  | EXPECT_EQ(dif_kmac_config_is_locked(&kmac_, &lock), kDifOk); | 
|  | EXPECT_FALSE(lock); | 
|  | } | 
|  |  | 
|  | TEST_F(ConfigLock, BadArg) { | 
|  | bool locked; | 
|  | EXPECT_DIF_BADARG(dif_kmac_config_is_locked(nullptr, &locked)); | 
|  | EXPECT_DIF_BADARG(dif_kmac_config_is_locked(&kmac_, nullptr)); | 
|  | } | 
|  |  | 
|  | class KmacEndTest : public KmacTest { | 
|  | protected: | 
|  | KmacEndTest() { op_state_.squeezing = true; } | 
|  | }; | 
|  |  | 
|  | TEST_F(KmacEndTest, Success) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_SQUEEZE_BIT, true}}); | 
|  | EXPECT_WRITE32(KMAC_CMD_REG_OFFSET, | 
|  | {{KMAC_CMD_CMD_OFFSET, KMAC_CMD_CMD_VALUE_DONE}}); | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_end(&kmac_, &op_state_)); | 
|  |  | 
|  | EXPECT_EQ(op_state_.squeezing, false); | 
|  | EXPECT_EQ(op_state_.append_d, false); | 
|  | EXPECT_EQ(op_state_.offset, 0); | 
|  | EXPECT_EQ(op_state_.r, 0); | 
|  | EXPECT_EQ(op_state_.d, 0); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacEndTest, BadArg) { | 
|  | EXPECT_DIF_BADARG(dif_kmac_end(nullptr, &op_state_)); | 
|  |  | 
|  | EXPECT_DIF_BADARG(dif_kmac_end(&kmac_, nullptr)); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacEndTest, Error) { | 
|  | op_state_.squeezing = false; | 
|  | EXPECT_EQ(dif_kmac_end(&kmac_, &op_state_), kDifError); | 
|  | } | 
|  |  | 
|  | class KmacConfigureTest : public KmacTest { | 
|  | protected: | 
|  | dif_kmac_config_t kmac_config_ = { | 
|  | .entropy_mode = kDifKmacEntropyModeIdle, | 
|  | .entropy_fast_process = false, | 
|  | .entropy_seed = {0xaa25b4bf, 0x48ce8fff, 0x5a78282a, 0x48465647, | 
|  | 0x70410fef}, | 
|  | .entropy_hash_threshold = 0x03ff, | 
|  | .entropy_wait_timer = 0xffff, | 
|  | .entropy_prescaler = 0x03ff, | 
|  | .message_big_endian = false, | 
|  | .output_big_endian = false, | 
|  | .sideload = false, | 
|  | .msg_mask = true, | 
|  | }; | 
|  | KmacConfigureTest() { | 
|  | config_reg_.entropy_hash_threshold = kmac_config_.entropy_hash_threshold, | 
|  | config_reg_.entropy_wait_timer = kmac_config_.entropy_wait_timer, | 
|  | config_reg_.entropy_prescaler = kmac_config_.entropy_prescaler, | 
|  | config_reg_.msg_big_endian = kmac_config_.message_big_endian; | 
|  | config_reg_.state_big_endian = kmac_config_.output_big_endian; | 
|  | config_reg_.entropy_mode = kmac_config_.entropy_mode; | 
|  | config_reg_.entropy_fast_process = kmac_config_.entropy_fast_process; | 
|  | config_reg_.sideload = kmac_config_.sideload; | 
|  | config_reg_.key_strength = 0; | 
|  | config_reg_.mode = 0; | 
|  | config_reg_.msg_mask = kmac_config_.msg_mask; | 
|  | } | 
|  | }; | 
|  |  | 
|  | TEST_F(KmacConfigureTest, Success) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_IDLE_BIT, true}}); | 
|  | EXPECT_WRITE32( | 
|  | KMAC_ENTROPY_PERIOD_REG_OFFSET, | 
|  | {{KMAC_ENTROPY_PERIOD_PRESCALER_OFFSET, kmac_config_.entropy_prescaler}, | 
|  | {KMAC_ENTROPY_PERIOD_WAIT_TIMER_OFFSET, | 
|  | kmac_config_.entropy_wait_timer}}); | 
|  | EXPECT_WRITE32_SHADOWED( | 
|  | KMAC_ENTROPY_REFRESH_THRESHOLD_SHADOWED_REG_OFFSET, | 
|  | {{KMAC_ENTROPY_REFRESH_THRESHOLD_SHADOWED_THRESHOLD_OFFSET, | 
|  | kmac_config_.entropy_hash_threshold}}); | 
|  | ExpectConfig(); | 
|  | ExpectEntropySeed(kmac_config_.entropy_seed); | 
|  | EXPECT_DIF_OK(dif_kmac_configure(&kmac_, kmac_config_)); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacConfigureTest, BadArg) { | 
|  | EXPECT_DIF_BADARG(dif_kmac_configure(NULL, kmac_config_)); | 
|  | kmac_config_.entropy_mode = (dif_kmac_entropy_mode_t)0xff; | 
|  | EXPECT_DIF_BADARG(dif_kmac_configure(&kmac_, kmac_config_)); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacConfigureTest, Locked) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_IDLE_BIT, false}}); | 
|  | EXPECT_EQ(dif_kmac_configure(&kmac_, kmac_config_), kDifLocked); | 
|  | } | 
|  |  | 
|  | class KmacStatusTest : public KmacTest { | 
|  | protected: | 
|  | dif_kmac_status_t status_; | 
|  | }; | 
|  |  | 
|  | TEST_F(KmacStatusTest, IdleFifoEmptySuccess) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_IDLE_BIT, true}, | 
|  | {KMAC_STATUS_FIFO_EMPTY_BIT, true}}); | 
|  | EXPECT_DIF_OK(dif_kmac_get_status(&kmac_, &status_)); | 
|  |  | 
|  | EXPECT_EQ(status_.sha3_state, kDifKmacSha3StateIdle); | 
|  | EXPECT_EQ(status_.fifo_depth, 0); | 
|  | EXPECT_EQ(status_.fifo_state, kDifKmacFifoStateEmpty); | 
|  | EXPECT_EQ(status_.faults, kDifKmacAlertNone); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacStatusTest, AbsorbingFifoPartialSuccess) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_ABSORB_BIT, true}, | 
|  | {KMAC_STATUS_FIFO_DEPTH_OFFSET, | 
|  | KMAC_PARAM_NUM_ENTRIES_MSG_FIFO}}); | 
|  | EXPECT_DIF_OK(dif_kmac_get_status(&kmac_, &status_)); | 
|  |  | 
|  | EXPECT_EQ(status_.sha3_state, kDifKmacSha3StateAbsorbing); | 
|  | EXPECT_EQ(status_.fifo_depth, KMAC_PARAM_NUM_ENTRIES_MSG_FIFO); | 
|  | EXPECT_EQ(status_.fifo_state, kDifKmacFifoStatePartial); | 
|  | EXPECT_EQ(status_.faults, kDifKmacAlertNone); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacStatusTest, SqueezingFifoFullSuccess) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_SQUEEZE_BIT, true}, | 
|  | {KMAC_STATUS_FIFO_DEPTH_OFFSET, 15}, | 
|  | {KMAC_STATUS_FIFO_FULL_BIT, true}}); | 
|  | EXPECT_DIF_OK(dif_kmac_get_status(&kmac_, &status_)); | 
|  |  | 
|  | EXPECT_EQ(status_.sha3_state, kDifKmacSha3StateSqueezing); | 
|  | EXPECT_EQ(status_.fifo_depth, 15); | 
|  | EXPECT_EQ(status_.fifo_state, kDifKmacFifoStateFull); | 
|  | EXPECT_EQ(status_.faults, kDifKmacAlertNone); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacStatusTest, AbsorbingFifoFullFatalFault) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, | 
|  | {{KMAC_STATUS_SHA3_ABSORB_BIT, true}, | 
|  | {KMAC_STATUS_FIFO_DEPTH_OFFSET, 5}, | 
|  | {KMAC_STATUS_FIFO_FULL_BIT, true}, | 
|  | {KMAC_STATUS_ALERT_FATAL_FAULT_BIT, true}}); | 
|  | EXPECT_DIF_OK(dif_kmac_get_status(&kmac_, &status_)); | 
|  |  | 
|  | EXPECT_EQ(status_.sha3_state, kDifKmacSha3StateAbsorbing); | 
|  | EXPECT_EQ(status_.fifo_depth, 5); | 
|  | EXPECT_EQ(status_.fifo_state, kDifKmacFifoStateFull); | 
|  | EXPECT_EQ(status_.faults, kDifKmacAlertFatalFault); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacStatusTest, AbsorbingFifoFullUpdateError) { | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, | 
|  | {{KMAC_STATUS_SHA3_ABSORB_BIT, true}, | 
|  | {KMAC_STATUS_FIFO_DEPTH_OFFSET, 2}, | 
|  | {KMAC_STATUS_FIFO_FULL_BIT, true}, | 
|  | {KMAC_STATUS_ALERT_RECOV_CTRL_UPDATE_ERR_BIT, true}}); | 
|  | EXPECT_DIF_OK(dif_kmac_get_status(&kmac_, &status_)); | 
|  |  | 
|  | EXPECT_EQ(status_.sha3_state, kDifKmacSha3StateAbsorbing); | 
|  | EXPECT_EQ(status_.fifo_depth, 2); | 
|  | EXPECT_EQ(status_.fifo_state, kDifKmacFifoStateFull); | 
|  | EXPECT_EQ(status_.faults, kDifKmacAlertRecovCtrlUpdate); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacStatusTest, BadArg) { | 
|  | EXPECT_DIF_BADARG(dif_kmac_get_status(nullptr, &status_)); | 
|  | EXPECT_DIF_BADARG(dif_kmac_get_status(&kmac_, nullptr)); | 
|  | } | 
|  |  | 
|  | class KmacGetErrorTest : public KmacTest { | 
|  | protected: | 
|  | static constexpr std::array<dif_kmac_error_t, 7> kErrors = { | 
|  | kDifErrorNone, | 
|  | kDifErrorKeyNotValid, | 
|  | kDifErrorSoftwarePushedMessageFifo, | 
|  | kDifErrorSoftwarePushedWrongCommand, | 
|  | kDifErrorEntropyWaitTimerExpired, | 
|  | kDifErrorEntropyModeIncorrect, | 
|  | kDifErrorUnknownError}; | 
|  | dif_kmac_error_t error_; | 
|  | KmacGetErrorTest() { op_state_.squeezing = true; } | 
|  | }; | 
|  | constexpr std::array<dif_kmac_error_t, 7> KmacGetErrorTest::kErrors; | 
|  |  | 
|  | TEST_F(KmacGetErrorTest, Success) { | 
|  | for (auto err : kErrors) { | 
|  | EXPECT_READ32(KMAC_ERR_CODE_REG_OFFSET, err); | 
|  | EXPECT_DIF_OK(dif_kmac_get_error(&kmac_, &error_)); | 
|  | EXPECT_EQ(error_, err); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(KmacGetErrorTest, BadArg) { | 
|  | EXPECT_DIF_BADARG(dif_kmac_get_error(nullptr, &error_)); | 
|  |  | 
|  | EXPECT_DIF_BADARG(dif_kmac_get_error(&kmac_, nullptr)); | 
|  | } | 
|  |  | 
|  | class KmacGetHashCounterTest : public KmacTest { | 
|  | protected: | 
|  | uint32_t hash_ctr_; | 
|  | }; | 
|  |  | 
|  | TEST_F(KmacGetHashCounterTest, Success) { | 
|  | EXPECT_READ32(KMAC_ENTROPY_REFRESH_HASH_CNT_REG_OFFSET, | 
|  | {{KMAC_PARAM_HASH_CNT_W, 0}}); | 
|  | EXPECT_DIF_OK(dif_kmac_get_hash_counter(&kmac_, &hash_ctr_)); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacGetHashCounterTest, BadArg) { | 
|  | EXPECT_DIF_BADARG(dif_kmac_get_hash_counter(nullptr, &hash_ctr_)); | 
|  |  | 
|  | EXPECT_DIF_BADARG(dif_kmac_get_hash_counter(&kmac_, nullptr)); | 
|  | } | 
|  |  | 
|  | class KmacSqueezeTest : public KmacTest { | 
|  | protected: | 
|  | dif_kmac_operation_state_t expected_op_state_ = { | 
|  | .squeezing = true, | 
|  | .append_d = false, | 
|  | .offset = 30, | 
|  | .r = 34, | 
|  | .d = 30, | 
|  | }; | 
|  |  | 
|  | uint32_t out_buffer_[8]; | 
|  | size_t processed_; | 
|  | static constexpr std::array<std::array<uint32_t, 64>, 2> kOutShares = { | 
|  | {{0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0x5AA5A55A, 0x5AA5A55A, | 
|  | 0x5AA5A55A, 0x5AA5A55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, | 
|  | 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, 0xA55AA55A, 0xA55AA55A, | 
|  | 0xA55AA55A, 0xA55AA55A, 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, | 
|  | 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0x5AA5A55A, 0x5AA5A55A, | 
|  | 0x5AA5A55A, 0x5AA5A55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, | 
|  | 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, 0xA55AA55A, 0xA55AA55A, | 
|  | 0xA55AA55A, 0xA55AA55A, 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, | 
|  | 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0x5AA5A55A, 0x5AA5A55A, | 
|  | 0x5AA5A55A, 0x5AA5A55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, | 
|  | 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A}, | 
|  | {0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0x5AA5A55A, 0x5AA5A55A, | 
|  | 0x5AA5A55A, 0x5AA5A55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, | 
|  | 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, 0xA55AA55A, 0xA55AA55A, | 
|  | 0xA55AA55A, 0xA55AA55A, 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, | 
|  | 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0x5AA5A55A, 0x5AA5A55A, | 
|  | 0x5AA5A55A, 0x5AA5A55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, | 
|  | 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, 0xA55AA55A, 0xA55AA55A, | 
|  | 0xA55AA55A, 0xA55AA55A, 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, | 
|  | 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0x5AA5A55A, 0x5AA5A55A, | 
|  | 0x5AA5A55A, 0x5AA5A55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, 0xA55AA55A, | 
|  | 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A, 0x5AA5A55A}}}; | 
|  |  | 
|  | KmacSqueezeTest() { | 
|  | op_state_.r = GetRateWords(256); | 
|  | op_state_.squeezing = false; | 
|  | op_state_.append_d = false; | 
|  | } | 
|  |  | 
|  | void ExpectAppendSize() { | 
|  | uint32_t d = op_state_.d * sizeof(uint32_t) * 8; | 
|  | uint8_t len = 1 + (d > 0xFF) + (d > 0xFFFF) + (d > 0xFFFFFF); | 
|  | uint8_t shift = len * 8; | 
|  | do { | 
|  | shift -= 8; | 
|  | EXPECT_WRITE8(KMAC_MSG_FIFO_REG_OFFSET, (d >> shift) & 0xFF); | 
|  | } while (shift); | 
|  | EXPECT_WRITE8(KMAC_MSG_FIFO_REG_OFFSET, len & 0xFF); | 
|  | } | 
|  |  | 
|  | void ExpectReadOutput(const uint32_t *share1, const uint32_t *share2, | 
|  | size_t len) { | 
|  | uint32_t offset = KMAC_STATE_REG_OFFSET; | 
|  | for (size_t i = 0; i < len; ++i) { | 
|  | // Read both shares from state register and combine using XOR. | 
|  | EXPECT_READ32(offset, share1[i]); | 
|  | EXPECT_READ32(offset + 0x100, share2[i]); | 
|  | offset += sizeof(uint32_t); | 
|  | } | 
|  | } | 
|  | }; | 
|  | constexpr std::array<std::array<uint32_t, 64>, 2> KmacSqueezeTest::kOutShares; | 
|  |  | 
|  | TEST_F(KmacSqueezeTest, GenerateExtraStatesSuccess) { | 
|  | uint32_t out_buffer[64]; | 
|  | op_state_.d = ARRAYSIZE(out_buffer); | 
|  |  | 
|  | EXPECT_WRITE32(KMAC_CMD_REG_OFFSET, | 
|  | {{KMAC_CMD_CMD_OFFSET, KMAC_CMD_CMD_VALUE_PROCESS}}); | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_SQUEEZE_BIT, true}}); | 
|  | ExpectReadOutput(kOutShares[0].data(), kOutShares[1].data(), 34); | 
|  | EXPECT_WRITE32(KMAC_CMD_REG_OFFSET, | 
|  | {{KMAC_CMD_CMD_OFFSET, KMAC_CMD_CMD_VALUE_RUN}}); | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_SQUEEZE_BIT, true}}); | 
|  | ExpectReadOutput(&kOutShares[0].data()[34], &kOutShares[1].data()[34], | 
|  | kOutShares[0].size() - 34); | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_squeeze(&kmac_, &op_state_, out_buffer, | 
|  | ARRAYSIZE(out_buffer), nullptr)); | 
|  |  | 
|  | EXPECT_EQ(op_state_, expected_op_state_); | 
|  |  | 
|  | std::array<uint32_t, ARRAYSIZE(out_buffer)> out; | 
|  | for (size_t i = 0; i < out.size(); i++) { | 
|  | out[i] = kOutShares[0][i] ^ kOutShares[1][i]; | 
|  | } | 
|  | EXPECT_THAT(out_buffer, ElementsAreArray(out)); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacSqueezeTest, FillOutBufferSuccess) { | 
|  | op_state_.d = ARRAYSIZE(out_buffer_); | 
|  | expected_op_state_.d = ARRAYSIZE(out_buffer_); | 
|  | expected_op_state_.offset = 8; | 
|  |  | 
|  | EXPECT_WRITE32(KMAC_CMD_REG_OFFSET, | 
|  | {{KMAC_CMD_CMD_OFFSET, KMAC_CMD_CMD_VALUE_PROCESS}}); | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, {{KMAC_STATUS_SHA3_SQUEEZE_BIT, true}}); | 
|  | ExpectReadOutput(kOutShares[0].data(), kOutShares[1].data(), | 
|  | ARRAYSIZE(out_buffer_)); | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_squeeze(&kmac_, &op_state_, out_buffer_, | 
|  | ARRAYSIZE(out_buffer_), nullptr)); | 
|  |  | 
|  | EXPECT_EQ(op_state_, expected_op_state_); | 
|  |  | 
|  | std::array<uint32_t, ARRAYSIZE(out_buffer_)> out; | 
|  | for (size_t i = 0; i < out.size(); i++) { | 
|  | out[i] = kOutShares[0][i] ^ kOutShares[1][i]; | 
|  | } | 
|  | EXPECT_THAT(out_buffer_, ElementsAreArray(out)); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacSqueezeTest, AppendSizeSuccess) { | 
|  | op_state_.append_d = true; | 
|  | op_state_.d = ARRAYSIZE(out_buffer_); | 
|  | expected_op_state_.append_d = true; | 
|  | expected_op_state_.d = ARRAYSIZE(out_buffer_); | 
|  | expected_op_state_.r = GetRateWords(256); | 
|  | expected_op_state_.offset = 0; | 
|  |  | 
|  | ExpectAppendSize(); | 
|  | EXPECT_WRITE32(KMAC_CMD_REG_OFFSET, | 
|  | {{KMAC_CMD_CMD_OFFSET, KMAC_CMD_CMD_VALUE_PROCESS}}); | 
|  | EXPECT_DIF_OK(dif_kmac_squeeze(&kmac_, &op_state_, nullptr, 0, nullptr)); | 
|  |  | 
|  | EXPECT_EQ(op_state_, expected_op_state_); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacSqueezeTest, JustProcessSuccess) { | 
|  | expected_op_state_.d = 0; | 
|  | expected_op_state_.r = GetRateWords(256); | 
|  | expected_op_state_.offset = 0; | 
|  | EXPECT_WRITE32(KMAC_CMD_REG_OFFSET, | 
|  | {{KMAC_CMD_CMD_OFFSET, KMAC_CMD_CMD_VALUE_PROCESS}}); | 
|  |  | 
|  | EXPECT_DIF_OK(dif_kmac_squeeze(&kmac_, &op_state_, nullptr, 0, nullptr)); | 
|  | EXPECT_EQ(op_state_, expected_op_state_); | 
|  | EXPECT_EQ(op_state_.d, 0); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacSqueezeTest, BadArg) { | 
|  | EXPECT_DIF_BADARG(dif_kmac_squeeze(NULL, &op_state_, out_buffer_, | 
|  | ARRAYSIZE(out_buffer_), nullptr)); | 
|  | EXPECT_DIF_BADARG(dif_kmac_squeeze(&kmac_, nullptr, out_buffer_, | 
|  | ARRAYSIZE(out_buffer_), nullptr)); | 
|  | EXPECT_DIF_BADARG(dif_kmac_squeeze(&kmac_, &op_state_, nullptr, | 
|  | ARRAYSIZE(out_buffer_), nullptr)); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacSqueezeTest, StarteMachineError) { | 
|  | op_state_.d = ARRAYSIZE(out_buffer_) / 2; | 
|  | EXPECT_WRITE32(KMAC_CMD_REG_OFFSET, | 
|  | {{KMAC_CMD_CMD_OFFSET, KMAC_CMD_CMD_VALUE_PROCESS}}); | 
|  |  | 
|  | EXPECT_EQ(dif_kmac_squeeze(&kmac_, &op_state_, out_buffer_, | 
|  | ARRAYSIZE(out_buffer_), nullptr), | 
|  | kDifError); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacSqueezeTest, RequestLessDataThanFixedLenError) { | 
|  | op_state_.d = ARRAYSIZE(out_buffer_); | 
|  |  | 
|  | EXPECT_WRITE32(KMAC_CMD_REG_OFFSET, | 
|  | {{KMAC_CMD_CMD_OFFSET, KMAC_CMD_CMD_VALUE_PROCESS}}); | 
|  | EXPECT_READ32(KMAC_STATUS_REG_OFFSET, | 
|  | {{KMAC_STATUS_SHA3_SQUEEZE_BIT, false}}); | 
|  | EXPECT_READ32(KMAC_INTR_STATE_REG_OFFSET, | 
|  | {{KMAC_INTR_STATE_KMAC_ERR_BIT, true}}); | 
|  |  | 
|  | EXPECT_EQ(dif_kmac_squeeze(&kmac_, &op_state_, out_buffer_, | 
|  | ARRAYSIZE(out_buffer_), nullptr), | 
|  | kDifError); | 
|  | } | 
|  |  | 
|  | class KmacResetTest : public KmacTest {}; | 
|  |  | 
|  | TEST_F(KmacResetTest, Success) { | 
|  | EXPECT_READ32(KMAC_CFG_SHADOWED_REG_OFFSET, 0); | 
|  | EXPECT_WRITE32_SHADOWED(KMAC_CFG_SHADOWED_REG_OFFSET, | 
|  | {{KMAC_CFG_SHADOWED_ERR_PROCESSED_BIT, true}}); | 
|  | EXPECT_DIF_OK(dif_kmac_reset(&kmac_, &op_state_)); | 
|  | EXPECT_EQ(op_state_.squeezing, false); | 
|  | EXPECT_EQ(op_state_.append_d, false); | 
|  | EXPECT_EQ(op_state_.offset, 0); | 
|  | EXPECT_EQ(op_state_.r, 0); | 
|  | EXPECT_EQ(op_state_.d, 0); | 
|  | } | 
|  |  | 
|  | TEST_F(KmacResetTest, BadArg) { | 
|  | EXPECT_DIF_BADARG(dif_kmac_reset(nullptr, &op_state_)); | 
|  |  | 
|  | EXPECT_DIF_BADARG(dif_kmac_reset(&kmac_, nullptr)); | 
|  | } | 
|  |  | 
|  | }  // namespace dif_kmac_unittest |