Software APIs
entropy_src_kat_impl.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 #include "sw/device/tests/entropy_src_kat_impl.h"
5 
11 #include "sw/device/lib/testing/entropy_src_testutils.h"
12 #include "sw/device/lib/testing/entropy_testutils.h"
13 #include "sw/device/lib/testing/test_framework/check.h"
14 
15 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" // Generated.
16 
17 enum {
18  /**
19  * The size of the buffer used in firmware to process the entropy bits in
20  * firmware override mode.
21  */
22  kEntropyFifoBufferSize = 12,
23  /**
24  * The number of attemps for performing operations before timing out.
25  */
26  kKatTestTimeoutAttempts = 256,
27 };
28 
29 /**
30  * Cleanly disables the SHA3 conditioner while in SHA3 mode, prompting
31  * the release of a conditioned seed.
32  *
33  * If stopping the conditioner fails, due to pending data keep trying for
34  * at most kKatTestTimeoutAttempts.
35  *
36  * @param entropy An entropy source instance.
37  */
38 static void stop_sha3_conditioner(dif_entropy_src_t *entropy_src) {
39  uint32_t fail_count = 0;
40  dif_result_t op_result;
41 
42  do {
43  op_result = dif_entropy_src_conditioner_stop(entropy_src);
44  if (op_result == kDifIpFifoFull) {
45  fail_count++;
46  CHECK(fail_count < kKatTestTimeoutAttempts);
47  } else {
48  CHECK_DIF_OK(op_result);
49  }
50  } while (op_result == kDifIpFifoFull);
51 }
52 
53 /**
54  * Flushes any previously absorbed entropy from the SHA3 conditioning block.
55  *
56  * @param entropy An entropy source instance.
57  */
58 static void flush_sha3_conditioner(dif_entropy_src_t *entropy_src) {
59  // Start and stop the conditioner, without adding any new entropy.
60  CHECK_DIF_OK(dif_entropy_src_conditioner_start(entropy_src));
61  stop_sha3_conditioner(entropy_src);
62 
63  int fail_count = 0;
64 
65  // Read (and discard) the resulting seed.
66  uint32_t got[kEntropyFifoBufferSize];
67  size_t total = 0;
68  do {
69  dif_result_t op_result =
70  dif_entropy_src_non_blocking_read(entropy_src, &got[total]);
71  if (op_result == kDifUnavailable) {
72  fail_count++;
73  CHECK(fail_count < kKatTestTimeoutAttempts);
74  } else {
75  CHECK_DIF_OK(op_result);
76  total++;
77  }
78  } while (total < ARRAYSIZE(got));
79 }
80 
81 void entropy_src_kat_test(dif_entropy_src_t *entropy_src) {
82  CHECK_STATUS_OK(entropy_testutils_stop_all());
83  CHECK_STATUS_OK(entropy_src_testutils_fw_override_enable(
84  entropy_src, kEntropyFifoBufferSize,
85  /*route_to_firmware=*/true,
86  /*bypass_conditioner=*/false));
87 
88  // Though most of the entropy_src state is cleared on disable, the
89  // SHA3 conditioner accumulates entropy even from aborted seeds. For
90  // the KAT though, we must clear any previously absorbed entropy.
91  flush_sha3_conditioner(entropy_src);
92 
93  const uint32_t kInputMsg[kEntropyFifoBufferSize] = {
94  0xa52a0da9, 0xcae141b2, 0x6d5bab9d, 0x2c3e5cc0, 0x225afc93, 0x5d31a610,
95  0x91b7f960, 0x0d566bb3, 0xef35e170, 0x94ba7d8e, 0x534eb741, 0x6b60b0da,
96  };
97 
98  CHECK_DIF_OK(dif_entropy_src_conditioner_start(entropy_src));
99 
100  dif_result_t op_result;
101  uint32_t fail_count = 0;
102  uint32_t count;
103  uint32_t total = 0;
104 
105  // Load the input data.
106  do {
108  entropy_src, kInputMsg + total, ARRAYSIZE(kInputMsg) - total, &count);
109  if (op_result == kDifIpFifoFull) {
110  fail_count++;
111  CHECK(fail_count < kKatTestTimeoutAttempts);
112  } else {
113  fail_count = 0;
114  CHECK_DIF_OK(op_result);
115  total += count;
116  }
117  } while (total < ARRAYSIZE(kInputMsg));
118 
119  // Cleanly disable the conditioner.
120  stop_sha3_conditioner(entropy_src);
121 
122  fail_count = 0;
123  uint32_t got[kEntropyFifoBufferSize];
124  total = 0;
125  do {
126  op_result = dif_entropy_src_non_blocking_read(entropy_src, &got[total]);
127  if (op_result == kDifUnavailable) {
128  fail_count++;
129  CHECK(fail_count < kKatTestTimeoutAttempts);
130  } else {
131  CHECK_DIF_OK(op_result);
132  total++;
133  }
134  } while (total < ARRAYSIZE(got));
135 
136  const uint32_t kExpectedDigest[kEntropyFifoBufferSize] = {
137  0x1c88164a, 0x5ff456e1, 0x0845dbdf, 0xbe233f8e, 0x7a5a4c1b, 0x5d31356a,
138  0x751cc536, 0x337375f2, 0x85a1ac19, 0x1333abd4, 0xf745fe0f, 0xc5bbf151,
139  };
140 
141  CHECK_ARRAYS_EQ(got, kExpectedDigest, kEntropyFifoBufferSize,
142  "Unexpected digest value.");
143 }