Software APIs
hash_sha2.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/hmac.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/sha2.h"
14 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/utils.h"
15 
16 enum {
17  /**
18  * Number of bits needed to represent the `tree` field.
19  */
20  kSpxTreeBits = kSpxTreeHeight * (kSpxD - 1),
21  /**
22  * Number of bytes needed to represent the `tree` field.
23  */
24  kSpxTreeBytes = (kSpxTreeBits + 7) / 8,
25  /**
26  * Number of bits needed to represent a leaf index.
27  */
28  kSpxLeafBits = kSpxTreeHeight,
29  /**
30  * Number of bytes needed to represent a leaf index.
31  */
32  kSpxLeafBytes = (kSpxLeafBits + 7) / 8,
33  /**
34  * Number of bytes needed for the message digest.
35  */
36  kSpxDigestBytes = kSpxForsMsgBytes + kSpxTreeBytes + kSpxLeafBytes,
37  /**
38  * Number of 32-bit words needed for the message digest.
39  *
40  * Rounded up if necessary.
41  */
42  kSpxDigestWords = (kSpxDigestBytes + sizeof(uint32_t) - 1) / sizeof(uint32_t),
43 };
44 
45 static_assert(
46  kSpxTreeBits <= 64,
47  "For given height and depth, 64 bits cannot represent all subtrees.");
48 static_assert(
49  kSpxLeafBits <= 32,
50  "For the given height, 32 bits is not large enough for a leaf index.");
51 
52 inline rom_error_t spx_hash_initialize(spx_ctx_t *ctx) {
53  hmac_sha256_configure(/*big_endian_digest=*/true);
54 
55  // Save state for the first part of `thash`: public key seed + padding.
56  hmac_sha256_start();
57  hmac_sha256_update_words(ctx->pub_seed, kSpxNWords);
58  uint32_t padding[kSpxSha2BlockNumWords - kSpxNWords];
59  memset(padding, 0, sizeof(padding));
60  hmac_sha256_update_words(padding, ARRAYSIZE(padding));
61  hmac_sha256_save(&ctx->state_seeded);
62  return kErrorOk;
63 }
64 
65 rom_error_t spx_hash_message(
66  const uint32_t *R, const uint32_t *pk, const uint8_t *msg_prefix_1,
67  size_t msg_prefix_1_len, const uint8_t *msg_prefix_2,
68  size_t msg_prefix_2_len, const uint8_t *msg_prefix_3,
69  size_t msg_prefix_3_len, const uint8_t *msg, size_t msg_len,
70  uint8_t *digest, uint64_t *tree, uint32_t *leaf_idx) {
71  uint32_t seed[kSpxDigestWords + (2 * kSpxNWords)] = {0};
72  // H_msg: MGF1-SHA256(R || PK.seed || SHA256(R || PK.seed || PK.root || M))
73  memcpy(seed, R, kSpxN);
74  memcpy(&seed[kSpxNWords], pk, kSpxN);
75  hmac_sha256_start();
76  hmac_sha256_update_words(R, kSpxNWords);
77  hmac_sha256_update_words(pk, kSpxPkWords);
78  hmac_sha256_update(msg_prefix_1, msg_prefix_1_len);
79  hmac_sha256_update(msg_prefix_2, msg_prefix_2_len);
80  hmac_sha256_update(msg_prefix_3, msg_prefix_3_len);
81  hmac_sha256_update(msg, msg_len);
82  hmac_sha256_process();
83  hmac_sha256_final_truncated(&seed[2 * kSpxNWords], kSpxDigestWords);
84 
85  uint32_t buf[kSpxDigestWords] = {0};
86  mgf1_sha256(seed, ARRAYSIZE(seed), ARRAYSIZE(buf), buf);
87 
88  unsigned char *bufp = (unsigned char *)buf;
89  memcpy(digest, bufp, kSpxForsMsgBytes);
90  bufp += kSpxForsMsgBytes;
91 
92  if (kSpxTreeBits == 0) {
93  *tree = 0;
94  } else {
95  *tree = spx_utils_bytes_to_u64(bufp, kSpxTreeBytes);
96  *tree &= (~(uint64_t)0) >> (64 - kSpxTreeBits);
97  bufp += kSpxTreeBytes;
98  }
99 
100  *leaf_idx = (uint32_t)spx_utils_bytes_to_u64(bufp, kSpxLeafBytes);
101  *leaf_idx &= (~(uint32_t)0) >> (32 - kSpxLeafBits);
102 
103  return kErrorOk;
104 }