Software APIs
kmac_entropy_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/entropy_testutils.h"
10 #include "sw/device/lib/testing/test_framework/check.h"
12 
13 #include "kmac_regs.h" // Generated.
14 
15 static_assert(kDtKmacCount >= 1,
16  "This test requires at least one KMAC instance");
17 
18 static dt_kmac_t kTestKmac = (dt_kmac_t)0;
19 
20 OTTF_DEFINE_TEST_CONFIG();
21 
22 /**
23  * Struct to pack timeout values.
24  */
25 typedef struct kmac_edn_timeout {
26  uint16_t prescaler;
27  uint16_t wait_timer;
28  // Whether we expect timeout for hard-coded (`prescaler`, `wait_timer`) pairs
29  bool timeout_expected;
31 
32 /**
33  * Define various timer values to be used in the test.
34  */
35 static const kmac_edn_timeout_t kTestTimeoutVals[] = {
36  {
37  .prescaler = 0x000,
38  .wait_timer = 0x0001,
39  .timeout_expected = true,
40  },
41  {
42  .prescaler = 0x000,
43  .wait_timer = 0x0001,
44  .timeout_expected = true,
45  },
46  {
47  .prescaler = 0x3ff,
48  .wait_timer = 0xffff,
49  .timeout_expected = false,
50  },
51  {
52  .prescaler = 0x3ff,
53  .wait_timer = 0xffff,
54  .timeout_expected = false,
55  },
56 };
57 
58 enum {
59  kKmacTimeoutTestCount = ARRAYSIZE(kTestTimeoutVals),
60  // Maxiumum digest size in bytes
61  kKmacDigestLenMax = 100,
62  kKmacEntropyHashThresholdStall = 2,
63  kNumIterationsStall = kKmacEntropyHashThresholdStall,
64 };
65 
66 /**
67  * KMAC test description.
68  */
69 typedef struct kmac_test {
71  dif_kmac_key_t key;
72 
73  const char *message;
74  size_t message_len;
75 
76  const char *customization_string;
77  size_t customization_string_len;
78 
79  const uint32_t digest[kKmacDigestLenMax];
80  size_t digest_len;
81  bool digest_len_is_fixed;
82 } kmac_test_t;
83 
84 /**
85  * A single KMAC example:
86  * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMAC_samples.pdf
87  */
88 const kmac_test_t kKmacTestVector = {
89  .mode = kDifKmacModeKmacLen256,
90  .key =
92  .share0 = {0x43424140, 0x47464544, 0x4b4a4948, 0x4f4e4f4c,
93  0x53525150, 0x57565554, 0x5b5a5958, 0x5f5e5d5c},
94  .share1 = {0},
95  .length = kDifKmacKeyLen256,
96  },
97  .message =
98  "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
99  "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
100  "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
101  "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
102  "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
103  "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
104  "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
105  "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
106  "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
107  "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
108  "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
109  "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
110  "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
111  .message_len = 200,
112  .customization_string = "My Tagged Application",
113  .customization_string_len = 21,
114  .digest = {0x1c73bed5, 0x73d74e95, 0x59bb4628, 0xe3a8e3db, 0x7ae7830f,
115  0x5944ff4b, 0xb4c2f1f2, 0xceb8ebec, 0xc601ba67, 0x57b88a2e,
116  0x9b492d8d, 0x6727bbd1, 0x90117868, 0x6a300a02, 0x1d28de97,
117  0x5d3030cc},
118  .digest_len = 16,
119  .digest_len_is_fixed = false,
120 };
121 
122 // Function to disable entropy complex
123 status_t disable_entropy_complex(void) {
124  // Using entropy test utility to stop all EDN0, EDN1, CSRNG, and the Entropy
125  // Source
126  TRY(entropy_testutils_stop_all());
127  LOG_INFO("The entire entropy complex is stopped");
128  return OK_STATUS();
129 }
130 
131 // Function to enable entropy complex
132 status_t enable_entropy_complex(void) {
133  // Using entropy test utility to enable all EDN0, EDN1, CSRNG, and the
134  // Entropy Source
135  TRY(entropy_testutils_auto_mode_init());
136  LOG_INFO("The entire entropy complex is enabled");
137  return OK_STATUS();
138 }
139 
140 status_t test_kmac_entropy_stall(void) {
141  LOG_INFO("Running KMAC ENTROPY STALL test...");
142 
143  // Initialize KMAC HWIP
144  dif_kmac_t kmac;
145  CHECK_DIF_OK(dif_kmac_init_from_dt(kTestKmac, &kmac));
146 
147  // Configure KMAC to use EDN entropy
148  dif_kmac_config_t config = {
149  .entropy_mode = kDifKmacEntropyModeEdn,
150  .entropy_fast_process = false,
151  .entropy_hash_threshold = kKmacEntropyHashThresholdStall,
152  .message_big_endian = false,
153  .output_big_endian = false,
154  .sideload = false,
155  .msg_mask = false,
156  .entropy_prescaler = 0x3ff,
157  .entropy_wait_timer = 0xffff,
158  };
159 
160  // Handle string encoding
163  kKmacTestVector.customization_string,
164  kKmacTestVector.customization_string_len, &str_buffer));
165 
166  // When customization_string is empty, use NULL to activate empty str path
167  dif_kmac_customization_string_t *str_buffer_ptr =
168  kKmacTestVector.customization_string_len == 0 ? NULL : &str_buffer;
169 
170  size_t test_digest_len =
171  kKmacTestVector.digest_len_is_fixed ? kKmacTestVector.digest_len : 0;
172 
173  uint32_t hash_ctr;
174  CHECK_DIF_OK(dif_kmac_get_hash_counter(&kmac, &hash_ctr));
175  for (size_t i = 0; i < kNumIterationsStall; i++) {
176  LOG_INFO("loop_ctr = %d", i);
177 
178  if (i == kKmacEntropyHashThresholdStall - 1) {
179  LOG_INFO("Disabling entropy complex to trigger a stall");
180  TRY(disable_entropy_complex());
181  }
182 
183  TRY(dif_kmac_configure(&kmac, config));
184 
185  dif_kmac_operation_state_t kmac_operation_state;
186  TRY(dif_kmac_mode_kmac_start(&kmac, &kmac_operation_state,
187  kKmacTestVector.mode, test_digest_len,
188  &kKmacTestVector.key, str_buffer_ptr));
189 
190  TRY(dif_kmac_absorb(&kmac, &kmac_operation_state, kKmacTestVector.message,
191  kKmacTestVector.message_len, NULL));
192  CHECK(kKmacDigestLenMax >= kKmacTestVector.digest_len);
193 
194  uint32_t out[kKmacDigestLenMax];
195  if (i == kKmacEntropyHashThresholdStall - 1) {
196  // Manually issue a squeeze command to check whether KMAC stalls if
197  // entropy complex is disabled.
198  uint32_t cmd_reg = bitfield_field32_write(0, KMAC_CMD_CMD_FIELD,
199  KMAC_CMD_CMD_VALUE_PROCESS);
200  mmio_region_write32(kmac.base_addr, KMAC_CMD_REG_OFFSET, cmd_reg);
201  kmac_operation_state.squeezing = true;
202  // Check status.
203  dif_kmac_status_t kmac_status;
204  CHECK_DIF_OK(dif_kmac_get_status(&kmac, &kmac_status));
205  TRY_CHECK(kmac_status.sha3_state != kDifKmacSha3StateSqueezing,
206  "KMAC not stalling");
207  LOG_INFO("KMAC stalled as expected after disabling entropy complex");
208  // Re-enable entropy complex and check whether we can resume operation.
209  TRY(enable_entropy_complex());
210  CHECK_DIF_OK(dif_kmac_get_status(&kmac, &kmac_status));
211  TRY_CHECK(kmac_status.sha3_state == kDifKmacSha3StateSqueezing,
212  "KMAC not in squeeze state");
213  LOG_INFO("KMAC is is squeeze state after enabling entropy complex");
214  } else {
215  TRY(dif_kmac_squeeze(&kmac, &kmac_operation_state, out,
216  kKmacTestVector.digest_len,
217  /*processed=*/NULL, /*capacity=*/NULL));
218  }
219  // Flush out the result and check correctness
220  CHECK_DIF_OK(dif_kmac_end(&kmac, &kmac_operation_state));
221  }
222 
223  return OK_STATUS();
224 }
225 
226 status_t test_kmac_entropy(void) {
227  LOG_INFO("Running KMAC ENTROPY test...");
228 
229  // Initialize KMAC HWIP
230  dif_kmac_t kmac;
231  CHECK_DIF_OK(dif_kmac_init_from_dt(kTestKmac, &kmac));
232 
233  // Configure KMAC to use EDN entropy
234  dif_kmac_config_t config = {
235  .entropy_mode = kDifKmacEntropyModeEdn,
236  .entropy_fast_process = false,
237  // In the last iteration, we expect to see that hash_ctr rewinds to 0
238  .entropy_hash_threshold = kKmacTimeoutTestCount,
239  .message_big_endian = false,
240  .output_big_endian = false,
241  .sideload = false,
242  .msg_mask = false,
243  };
244 
245  // Handle string encoding
248  kKmacTestVector.customization_string,
249  kKmacTestVector.customization_string_len, &str_buffer));
250 
251  // When customization_string is empty, use NULL to activate empty str path
252  dif_kmac_customization_string_t *str_buffer_ptr =
253  kKmacTestVector.customization_string_len == 0 ? NULL : &str_buffer;
254 
255  size_t test_digest_len =
256  kKmacTestVector.digest_len_is_fixed ? kKmacTestVector.digest_len : 0;
257 
258  for (size_t i = 0; i < kKmacTimeoutTestCount; ++i) {
259  LOG_INFO("loop_ctr = %d", i);
260 
261  kmac_edn_timeout_t timeout_test = kTestTimeoutVals[i];
262 
263  config.entropy_prescaler = timeout_test.prescaler;
264  config.entropy_wait_timer = timeout_test.wait_timer;
265 
266  CHECK_DIF_OK(dif_kmac_configure(&kmac, config));
267 
268  dif_kmac_operation_state_t kmac_operation_state;
269  CHECK_DIF_OK(dif_kmac_mode_kmac_start(
270  &kmac, &kmac_operation_state, kKmacTestVector.mode, test_digest_len,
271  &kKmacTestVector.key, str_buffer_ptr));
272 
273  CHECK_DIF_OK(dif_kmac_absorb(&kmac, &kmac_operation_state,
274  kKmacTestVector.message,
275  kKmacTestVector.message_len, NULL));
276 
277  CHECK(kKmacDigestLenMax >= kKmacTestVector.digest_len);
278 
279  // This is where timeout might happen, so we handle dif return manually
280  uint32_t out[kKmacDigestLenMax];
281  dif_result_t res = dif_kmac_squeeze(&kmac, &kmac_operation_state, out,
282  kKmacTestVector.digest_len,
283  /*processed=*/NULL, /*capacity=*/NULL);
284 
285  // It is OK to get kDifError at this point because of possible timeout
286  CHECK(res == kDifOk || res == kDifError);
287 
288  // Check if there is a new error
289  bool irq_err_pending;
290  CHECK_DIF_OK(
291  dif_kmac_irq_is_pending(&kmac, kDifKmacIrqKmacErr, &irq_err_pending));
292  if (irq_err_pending) {
293  dif_kmac_error_t err_status;
294  uint32_t err_info;
295  CHECK_DIF_OK(dif_kmac_get_error(&kmac, &err_status, &err_info));
296  CHECK(err_status == kDifErrorEntropyWaitTimerExpired,
297  "Error other than EDN timeout occurred.");
298  LOG_INFO("EDN timed out.");
299  } else {
300  LOG_INFO("EDN seed received before timeout.");
301  }
302 
303  // At this point, irq_err_pending says if timeout is observed
304  CHECK(irq_err_pending == timeout_test.timeout_expected,
305  "EDN timeout expectation doesn't match observation.");
306 
307  // Flush out the result and check correctness
308  CHECK_DIF_OK(dif_kmac_end(&kmac, &kmac_operation_state));
309 
310  // If err interrupt is generated, we need clean-up
311  if (irq_err_pending) {
312  // Clean INTR_STATE
313  CHECK_DIF_OK(dif_kmac_irq_acknowledge_all(&kmac));
314 
315  // Reset FSM by setting `err_processed` bit
316  CHECK_DIF_OK(dif_kmac_reset(&kmac, &kmac_operation_state));
317 
318  // At this point, we expect that there are no remaining interrupts.
319  dif_kmac_irq_state_snapshot_t intr_snapshot;
320  CHECK_DIF_OK(dif_kmac_irq_get_state(&kmac, &intr_snapshot));
321  CHECK(intr_snapshot == 0,
322  "INTR_STATE is non-zero after timeout clean-up.");
323 
324  bool is_kmac_locked;
325  CHECK_DIF_OK(dif_kmac_config_is_locked(&kmac, &is_kmac_locked));
326  CHECK(!is_kmac_locked, "KMAC still locked after timeout clean-up.");
327  }
328 
329  // We check whether hash counter is increasing/rewinding as expected
330  uint32_t hash_ctr;
331  CHECK_DIF_OK(dif_kmac_get_hash_counter(&kmac, &hash_ctr));
332  CHECK(hash_ctr == (i + 1) % (kKmacTimeoutTestCount),
333  "Hash counter increment is wrong.");
334  LOG_INFO("hash_ctr = %d", hash_ctr);
335  }
336 
337  return OK_STATUS();
338 }
339 
340 bool test_main(void) {
341  static status_t result;
342 
343  EXECUTE_TEST(result, test_kmac_entropy);
344  EXECUTE_TEST(result, test_kmac_entropy_stall);
345 
346  return status_ok(result);
347 }