Software APIs
utils.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 //
5 // Derived from code in the SPHINCS+ reference implementation (CC0 license):
6 // https://github.com/sphincs/sphincsplus/blob/ed15dd78658f63288c7492c00260d86154b84637/ref/utils.c
7 
8 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/utils.h"
9 
11 #include "sw/device/silicon_creator/lib/drivers/hmac.h"
12 #include "sw/device/silicon_creator/lib/error.h"
13 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/address.h"
14 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/params.h"
15 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/thash.h"
16 
17 uint64_t spx_utils_bytes_to_u64(const uint8_t *in, size_t inlen) {
18  uint64_t retval = 0;
19  for (size_t i = 0; i < inlen; i++) {
20  // Perform native shift on u32 first to avoid __ashldi3 polyfill.
21  //
22  // The following code is equivalent to:
23  // retval |= ((uint64_t)in[i]) << (8 * (inlen - 1 - i));
24  //
25  // See also pull #11451.
26  size_t offset = 8 * (inlen - 1 - i);
27  if (offset < 32) {
28  retval |= ((uint32_t)in[i]) << offset;
29  } else {
30  retval |= ((uint64_t)(((uint32_t)in[i]) << (offset - 32))) << 32;
31  }
32  }
33  return retval;
34 }
35 
36 void spx_utils_compute_root(const uint32_t *leaf, uint32_t leaf_idx,
37  uint32_t idx_offset, const uint32_t *auth_path,
38  uint8_t tree_height, const spx_ctx_t *ctx,
39  spx_addr_t *addr, uint32_t *root) {
40  // Initialize working buffer.
41  uint32_t buffer[2 * kSpxNWords];
42  // Pointer to second half of buffer for convenience.
43  uint32_t *buffer_second = &buffer[kSpxNWords];
44 
45  // If leaf_idx is odd (last bit = 1), current path element is a right child
46  // and auth_path has to go left. Otherwise it is the other way around.
47  if (leaf_idx & 1) {
48  memcpy(buffer_second, leaf, kSpxN);
49  memcpy(buffer, auth_path, kSpxN);
50  } else {
51  memcpy(buffer, leaf, kSpxN);
52  memcpy(buffer_second, auth_path, kSpxN);
53  }
54  auth_path += kSpxNWords;
55 
56  for (uint8_t i = 0; i < tree_height - 1; i++) {
57  leaf_idx >>= 1;
58  idx_offset >>= 1;
59  // Set the address of the node we're creating.
60  spx_addr_tree_height_set(addr, i + 1);
61  spx_addr_tree_index_set(addr, leaf_idx + idx_offset);
62 
63  // Pick the right or left neighbor, depending on parity of the node.
64  uint32_t *hash_dst = (leaf_idx & 1) ? buffer_second : buffer;
65  uint32_t *auth_dst = (leaf_idx & 1) ? buffer : buffer_second;
66 
67  thash(buffer, /*inblocks=*/2, ctx, addr, hash_dst);
68  memcpy(auth_dst, auth_path, kSpxN);
69  auth_path += kSpxNWords;
70  }
71 
72  // The last iteration is exceptional; we do not copy an auth_path node.
73  leaf_idx >>= 1;
74  idx_offset >>= 1;
75  spx_addr_tree_height_set(addr, tree_height);
76  spx_addr_tree_index_set(addr, leaf_idx + idx_offset);
77  thash(buffer, 2, ctx, addr, root);
78 }