Software APIs
hash_shake.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/hash_shake.c
7 
9 #include "sw/device/silicon_creator/lib/drivers/kmac.h"
10 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/address.h"
11 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/hash.h"
12 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/params.h"
13 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/utils.h"
14 
15 enum {
16  /**
17  * Number of bits needed to represent the `tree` field.
18  */
19  kSpxTreeBits = kSpxTreeHeight * (kSpxD - 1),
20  /**
21  * Number of bytes needed to represent the `tree` field.
22  */
23  kSpxTreeBytes = (kSpxTreeBits + 7) / 8,
24  /**
25  * Number of bits needed to represent a leaf index.
26  */
27  kSpxLeafBits = kSpxTreeHeight,
28  /**
29  * Number of bytes needed to represent a leaf index.
30  */
31  kSpxLeafBytes = (kSpxLeafBits + 7) / 8,
32  /**
33  * Number of bytes needed for the message digest.
34  */
35  kSpxDigestBytes = kSpxForsMsgBytes + kSpxTreeBytes + kSpxLeafBytes,
36  /**
37  * Number of 32-bit words needed for the message digest.
38  *
39  * Rounded up if necessary.
40  */
41  kSpxDigestWords = (kSpxDigestBytes + sizeof(uint32_t) - 1) / sizeof(uint32_t),
42 };
43 
44 static_assert(
45  kSpxTreeBits <= 64,
46  "For given height and depth, 64 bits cannot represent all subtrees.");
47 static_assert(
48  kSpxLeafBits <= 32,
49  "For the given height, 32 bits is not large enough for a leaf index.");
50 
51 rom_error_t spx_hash_initialize(spx_ctx_t *ctx) {
52  return kmac_shake256_configure();
53 }
54 
56 rom_error_t spx_hash_message(const uint32_t *R, const uint32_t *pk,
57  const uint8_t *msg_prefix_1,
58  size_t msg_prefix_1_len,
59  const uint8_t *msg_prefix_2,
60  size_t msg_prefix_2_len, const uint8_t *msg,
61  size_t msg_len, uint8_t *digest, uint64_t *tree,
62  uint32_t *leaf_idx) {
63  uint32_t buf[kSpxDigestWords] = {0};
64  unsigned char *bufp = (unsigned char *)buf;
65 
66  HARDENED_RETURN_IF_ERROR(kmac_shake256_start());
67  kmac_shake256_absorb_words(R, kSpxNWords);
68  kmac_shake256_absorb_words(pk, kSpxPkWords);
69  kmac_shake256_absorb(msg_prefix_1, msg_prefix_1_len);
70  kmac_shake256_absorb(msg_prefix_2, msg_prefix_2_len);
71  kmac_shake256_absorb(msg, msg_len);
72  kmac_shake256_squeeze_start();
73  HARDENED_RETURN_IF_ERROR(kmac_shake256_squeeze_end(buf, kSpxDigestWords));
74 
75  memcpy(digest, bufp, kSpxForsMsgBytes);
76  bufp += kSpxForsMsgBytes;
77 
78  if (kSpxTreeBits == 0) {
79  *tree = 0;
80  } else {
81  *tree = spx_utils_bytes_to_u64(bufp, kSpxTreeBytes);
82  *tree &= (~(uint64_t)0) >> (64 - kSpxTreeBits);
83  bufp += kSpxTreeBytes;
84  }
85 
86  *leaf_idx = (uint32_t)spx_utils_bytes_to_u64(bufp, kSpxLeafBytes);
87  *leaf_idx &= (~(uint32_t)0) >> (32 - kSpxLeafBits);
88 
89  return kErrorOk;
90 }