Software APIs
kmac_entropy_stress_test.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
9 #include "sw/device/lib/testing/test_framework/check.h"
11 
13 #include "kmac_regs.h" // Generated.
14 
15 OTTF_DEFINE_TEST_CONFIG();
16 
17 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
18 
19 dif_kmac_config_t kKmacTestCases[] = {
20 
21  //////////////////////////////////////////////////////////////////////////////
22  // EDN Mode
23  //////////////////////////////////////////////////////////////////////////////
24 
25  // Entropy wait timer is zero
26  {
27  .entropy_mode = kDifKmacEntropyModeEdn,
28  .entropy_fast_process = false,
29  .entropy_hash_threshold = 8,
30  .entropy_wait_timer = 0,
31  .entropy_prescaler = 0,
32  },
33 
34  // Entropy wait timer is nonzero
35  {
36  .entropy_mode = kDifKmacEntropyModeEdn,
37  .entropy_fast_process = false,
38  .entropy_hash_threshold = 8,
39  .entropy_wait_timer = 0xffff,
40  .entropy_prescaler = 0x3ff,
41  },
42 
43  // Entropy refresh hash count is 0 -- expect no hash counter reset
44  {
45  .entropy_mode = kDifKmacEntropyModeEdn,
46  .entropy_fast_process = false,
47  .entropy_hash_threshold = 0,
48  .entropy_wait_timer = 0,
49  .entropy_prescaler = 1,
50  },
51 
52  // Entropy refresh hash count is 1023, the maximum
53  {
54  .entropy_mode = kDifKmacEntropyModeEdn,
55  .entropy_fast_process = false,
56  .entropy_hash_threshold = 1023,
57  .entropy_wait_timer = 0,
58  .entropy_prescaler = 1,
59  },
60 
61  //////////////////////////////////////////////////////////////////////////////
62  // SW Mode
63  //////////////////////////////////////////////////////////////////////////////
64 
65  // entropy_hash_threshold = 8; in SW mode, the hash counter will still be
66  // reset but entropy will not be refreshed
67  {
68  .entropy_mode = kDifKmacEntropyModeSoftware,
69  .entropy_fast_process = false,
70  .entropy_seed =
71  {
72  0x1234567,
73  0x1234567,
74  0x1234567,
75  0x1234567,
76  0x1234567,
77  },
78  .entropy_hash_threshold = 8,
79  .entropy_wait_timer = 0xffff,
80  .entropy_prescaler = 0x3ff,
81  },
82 
83  // entropy_hash_threshold = 0
84  {
85  .entropy_mode = kDifKmacEntropyModeSoftware,
86  .entropy_fast_process = false,
87  .entropy_seed =
88  {
89  0x1234567,
90  0x1234567,
91  0x1234567,
92  0x1234567,
93  0x1234567,
94  },
95  .entropy_hash_threshold = 0,
96  .entropy_wait_timer = 0xffff,
97  .entropy_prescaler = 0x3ff,
98  },
99 };
100 
101 enum {
102  kKmacDigestLenMax = 100,
103  kTestConfigCount = ARRAYSIZE(kKmacTestCases),
104  kKmacIterations = 1000,
105 
106  // ENTROPY_REFRESH_THRESHOLD_SHADOWED and ENTROPY_REFRESH_HASH_CNT registers
107  // are 10 bits wide, so the refresh threshold cannot be set higher and the
108  // hash counter cannot count higher than this value
109  kHashCntMax = 0x3ff,
110 };
111 
112 typedef struct kmac_test_vector {
114  dif_kmac_key_t key;
115 
116  const char *message;
117  size_t message_len;
118 
119  const char *customization_string;
120  size_t customization_string_len;
121 
122  const uint32_t digest[kKmacDigestLenMax];
123  size_t digest_len;
125 
126 /**
127  * A single KMAC test vector:
128  * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMAC_samples.pdf
129  */
130 const kmac_test_vector_t kKmacTestVector = {
131  .mode = kDifKmacModeKmacLen256,
132  .key =
133  (dif_kmac_key_t){
134  .share0 = {0x43424140, 0x47464544, 0x4b4a4948, 0x4f4e4f4c,
135  0x53525150, 0x57565554, 0x5b5a5958, 0x5f5e5d5c},
136  .share1 = {0},
137  .length = kDifKmacKeyLen256,
138  },
139  .message =
140  "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
141  "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
142  "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
143  "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
144  "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
145  "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
146  "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
147  "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
148  "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
149  "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
150  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
151  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
152  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
153  .message_len = 200,
154  .customization_string = "My Tagged Application",
155  .customization_string_len = 21,
156  .digest = {0x1c73bed5, 0x73d74e95, 0x59bb4628, 0xe3a8e3db, 0x7ae7830f,
157  0x5944ff4b, 0xb4c2f1f2, 0xceb8ebec, 0xc601ba67, 0x57b88a2e,
158  0x9b492d8d, 0x6727bbd1, 0x90117868, 0x6a300a02, 0x1d28de97,
159  0x5d3030cc},
160  .digest_len = 16,
161 };
162 
163 /**
164  * Run many KMAC operations with a particular entropy configuration.
165  *
166  * This test checks that the KMAC block does not produce any errors and that
167  * the hash counter behaves as expected.
168  */
169 status_t test_kmac_config(dif_kmac_config_t *test_case) {
170  // The ENTROPY_REFRESH_THRESHOLD_SHADOWED register is 10 bits wide and cannot
171  // be set to a value higher than kHashCntMax.
172  TRY_CHECK(
173  test_case->entropy_hash_threshold <= kHashCntMax,
174  "Invalid test case: entropy_hash_threshold too high; greater than %d",
175  kHashCntMax);
176 
177  dif_kmac_t kmac;
178  TRY(dif_kmac_init(mmio_region_from_addr(TOP_EARLGREY_KMAC_BASE_ADDR), &kmac));
179 
180  // Handle customization string
183  kKmacTestVector.customization_string,
184  kKmacTestVector.customization_string_len, &cust_str));
185 
186  // Configure the KMAC block with the config from the test case
187  test_case->message_big_endian = false;
188  test_case->output_big_endian = false;
189  test_case->sideload = false;
190  test_case->msg_mask = true;
191  TRY(dif_kmac_configure(&kmac, *test_case));
192 
193  // Manually clear the hash counter
194  uint32_t hash_count, expected_hash_count = 0;
195  uint32_t cmd_reg = mmio_region_read32(kmac.base_addr, KMAC_CMD_REG_OFFSET);
196  cmd_reg = bitfield_bit32_write(cmd_reg, KMAC_CMD_HASH_CNT_CLR_BIT, 1);
197  mmio_region_write32(kmac.base_addr, KMAC_CMD_REG_OFFSET, cmd_reg);
198  TRY(dif_kmac_get_hash_counter(&kmac, &hash_count));
199  TRY_CHECK(hash_count == 0, "Failed to clear hash counter");
200 
201  // Run many KMAC operations
202  for (size_t i = 0; i < kKmacIterations; i++) {
204  // Wait for the idle state
205  TRY(dif_kmac_poll_status(&kmac, KMAC_STATUS_SHA3_IDLE_BIT));
206  TRY(dif_kmac_mode_kmac_start(&kmac, &op_state, kKmacTestVector.mode,
207  kKmacTestVector.digest_len,
208  &kKmacTestVector.key, &cust_str));
209 
210  TRY(dif_kmac_absorb(&kmac, &op_state, kKmacTestVector.message,
211  kKmacTestVector.message_len,
212  /* processed=*/NULL));
213 
214  // All squeeze operations in this test are expected to succeed
215  uint32_t out[kKmacDigestLenMax];
216  TRY(dif_kmac_squeeze(&kmac, &op_state, out, kKmacTestVector.digest_len,
217  /*processed=*/NULL, /*capacity=*/NULL));
218 
219  // Check if the KMAC block is signaling any errors
220  bool irq_err_pending;
221  TRY(dif_kmac_irq_is_pending(&kmac, kDifKmacIrqKmacErr, &irq_err_pending));
222 
223  // If IrqKmacErr is pending, get the error status and abort
224  if (irq_err_pending) {
225  dif_kmac_error_t err_status;
226  TRY(dif_kmac_get_error(&kmac, &err_status, /*info=*/NULL));
227 
228  TRY_CHECK(!irq_err_pending, "KMAC error occurred: 0x%x", err_status);
229  }
230 
231  // Check the hash counter value
232  TRY(dif_kmac_get_hash_counter(&kmac, &hash_count));
233  if (test_case->entropy_hash_threshold != 0) {
234  expected_hash_count =
235  (expected_hash_count + 1) % test_case->entropy_hash_threshold;
236  } else {
237  // If the hash counter threshold is not enabled (i.e. set to 0), the hash
238  // counter maxes out at kHashCntMax and should not overflow
239  expected_hash_count = MIN(expected_hash_count + 1, kHashCntMax);
240  }
241  TRY_CHECK(expected_hash_count == hash_count,
242  "Unexpected hash counter value: Got %d, Expected %d", hash_count,
243  expected_hash_count);
244 
245  TRY(dif_kmac_end(&kmac, &op_state));
246  }
247 
248  return OK_STATUS();
249 }
250 
251 status_t test_kmac_entropy_stress(void) {
252  LOG_INFO("Running KMAC entropy stress test...");
253 
254  for (size_t i = 0; i < kTestConfigCount; i++) {
255  LOG_INFO("Running test case %d", i);
256  test_kmac_config(&kKmacTestCases[i]);
257  }
258 
259  LOG_INFO("DONE");
260  return OK_STATUS();
261 }
262 
263 bool test_main(void) {
264  static status_t result;
265  EXECUTE_TEST(result, test_kmac_entropy_stress);
266  return status_ok(result);
267 }