blob: 4f1c2b8ce361d5ccb6f7efd0abbc8366717ab3a3 [file] [log] [blame] [edit]
// 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;
}