Software APIs
kmac_endianess_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 
10 #include "sw/device/lib/testing/test_framework/check.h"
12 
14 
15 OTTF_DEFINE_TEST_CONFIG();
16 
17 /**
18  * KMAC test description.
19  */
20 typedef struct kmac_test {
22  dif_kmac_key_t key;
23 
24  // The message needs to be 32-bit aligned (see below).
25  const uint32_t *message_big_endian;
26  const uint32_t *message_little_endian;
27  size_t message_len;
28 
29  size_t digest_len;
30 } kmac_test_t;
31 
32 /**
33  * KMAC test.
34  *
35  * Example taken from:
36  * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMAC_samples.pdf
37  */
38 const uint32_t message_big_endian[] = {0x03020100, 0x07060504};
39 const uint32_t message_little_endian[] = {0x00010203, 0x04050607};
40 
41 const kmac_test_t kmac_test = {
42  // KMAC
43  .mode = kDifKmacModeKmacLen128,
44  .key =
46  .share0 = {0x43424140, 0x47464544, 0x4B4A4948, 0x4F4E4D4C,
47  0x53525150, 0x57565554, 0x5B5A5958, 0x5F5E5D5C},
48  .share1 = {0},
49  .length = kDifKmacKeyLen256,
50  },
51  .message_big_endian = message_big_endian,
52  .message_little_endian = message_little_endian,
53  .message_len = ARRAYSIZE(message_big_endian),
54  .digest_len = 8,
55 };
56 
57 /**
58  * Big to little endianess converter.
59  *
60  * Helper function to convert from big to little endian.
61  *
62  * @param big_endian the number in big endian representation.
63  * @return the number in little endian representation.
64  */
65 uint32_t big_to_little_endian(uint32_t big_endian) {
66  uint32_t little_endian = 0;
67  little_endian = (big_endian >> 24) & 0xff;
68  little_endian |= (big_endian >> 8) & 0xff00;
69  little_endian |= (big_endian << 8) & 0xff0000;
70  little_endian |= (big_endian << 24) & 0xff000000;
71 
72  return little_endian;
73 }
74 
75 /**
76  * Endianess test.
77  *
78  * This test runs the same KMAC operation four times with the following
79  * endianess configuration:
80  * - Little endian message, little endian digest.
81  * - Little endian message, big endian digest.
82  * - Big endian message, little endian digest.
83  * - Big endian message, big endian digest.
84  *
85  * The output of the little endian message and little endian digest is used as a
86  * reference output as this is the default configuration. The other outputs are
87  * accordingly converted and compared.
88  *
89  * @return OK or error.
90  */
91 status_t test_endianess(void) {
92  // Intialize KMAC hardware.
93  dif_kmac_t kmac;
94  dif_kmac_operation_state_t kmac_operation_state;
95  CHECK_DIF_OK(
96  dif_kmac_init(mmio_region_from_addr(TOP_EARLGREY_KMAC_BASE_ADDR), &kmac));
97 
98  // Test configurations.
99  char msg_log[4][7] = {"little", "little", "big", "big"};
100  char digest_log[4][7] = {"little", "big", "little", "big"};
101  bool msg_endianess_big[4] = {false, false, true, true};
102  bool digest_endianess_big[4] = {false, true, false, true};
103 
104  // Reference output for little endian message & digest.
105  uint32_t ref_out[kmac_test.digest_len];
106 
107  for (size_t it = 0; it < ARRAYSIZE(msg_endianess_big); it++) {
108  LOG_INFO("Testing %s endian message and %s endian digest.", msg_log[it],
109  digest_log[it]);
110 
112  .entropy_mode = kDifKmacEntropyModeSoftware,
113  .entropy_seed = {0xb153e3fe, 0x09596819, 0x3e85a6e8, 0xb6dcdaba,
114  0x50dc409c, 0x11e1ebd1},
115  .entropy_fast_process = kDifToggleEnabled,
116  .message_big_endian = msg_endianess_big[it],
117  .output_big_endian = digest_endianess_big[it],
118  };
119 
120  CHECK_DIF_OK(dif_kmac_configure(&kmac, config));
121  CHECK_DIF_OK(dif_kmac_mode_kmac_start(&kmac, &kmac_operation_state,
122  kmac_test.mode, kmac_test.digest_len,
123  &kmac_test.key, NULL));
124  const uint32_t *message;
125  if (msg_endianess_big[it]) {
126  message = kmac_test.message_big_endian;
127  } else {
128  message = kmac_test.message_little_endian;
129  }
130 
131  uint32_t out[kmac_test.digest_len];
132  size_t base_printf(const char *format, ...);
133  // The message needs to be word aligned data, otherwise the unaligned
134  // bytes will not be byte swapped.
135  CHECK_DIF_OK(dif_kmac_absorb(&kmac, &kmac_operation_state, message,
136  kmac_test.message_len * sizeof(uint32_t),
137  NULL));
138  CHECK_DIF_OK(dif_kmac_squeeze(&kmac, &kmac_operation_state, out,
139  kmac_test.digest_len, /*processed=*/NULL,
140  /*capacity=*/NULL));
141  CHECK_DIF_OK(dif_kmac_end(&kmac, &kmac_operation_state));
142 
143  if (msg_endianess_big[it] == false && digest_endianess_big[it] == false) {
144  // We use little endian message/digest as the reference output.
145  memcpy(ref_out, out, sizeof(ref_out));
146  } else if (digest_endianess_big[it] == true) {
147  // Got big endianess digest, convert to little endian and compare with
148  // reference digest.
149  uint32_t big_to_little[kmac_test.digest_len];
150  for (int i = 0; i < kmac_test.digest_len; i++) {
151  big_to_little[i] = big_to_little_endian(out[i]);
152  }
153  CHECK_ARRAYS_EQ(big_to_little, ref_out, kmac_test.digest_len);
154  } else {
155  // Got little endianess digest, compare with reference digest.
156  CHECK_ARRAYS_EQ(out, ref_out, kmac_test.digest_len);
157  }
158  }
159 
160  return OK_STATUS();
161 }
162 
163 bool test_main(void) {
164  test_endianess();
165  return true;
166 }