Software APIs
verify.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/sign.c
7 
8 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/verify.h"
9 
10 #include <stddef.h>
11 #include <stdint.h>
12 
14 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/address.h"
15 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/context.h"
16 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/fors.h"
17 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/hash.h"
18 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/params.h"
19 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/thash.h"
20 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/utils.h"
21 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/wots.h"
22 
23 static_assert(kSpxVerifySigWords * sizeof(uint32_t) == kSpxVerifySigBytes,
24  "kSpxVerifySigWords and kSpxVerifySigBytes do not match.");
25 static_assert(kSpxVerifyPkWords * sizeof(uint32_t) == kSpxVerifyPkBytes,
26  "kSpxVerifyPkWords and kSpxVerifyPkBytes do not match.");
27 static_assert(kSpxD <= UINT8_MAX, "kSpxD must fit into a uint8_t.");
28 rom_error_t spx_verify(const uint32_t *sig, const uint8_t *msg_prefix_1,
29  size_t msg_prefix_1_len, const uint8_t *msg_prefix_2,
30  size_t msg_prefix_2_len, const uint8_t *msg_prefix_3,
31  size_t msg_prefix_3_len, const uint8_t *msg,
32  size_t msg_len, const uint32_t *pk, uint32_t *root) {
33  spx_ctx_t ctx;
34  memcpy(ctx.pub_seed, pk, kSpxN);
35 
36  // This hook allows the hash function instantiation to do whatever
37  // preparation or computation it needs, based on the public seed.
38  HARDENED_RETURN_IF_ERROR(spx_hash_initialize(&ctx));
39 
40  spx_addr_t wots_addr = {.addr = {0}};
41  spx_addr_t tree_addr = {.addr = {0}};
42  spx_addr_t wots_pk_addr = {.addr = {0}};
43  spx_addr_type_set(&wots_addr, kSpxAddrTypeWots);
44  spx_addr_type_set(&tree_addr, kSpxAddrTypeHashTree);
45  spx_addr_type_set(&wots_pk_addr, kSpxAddrTypeWotsPk);
46 
47  // Derive the message digest and leaf index from R || PK || M.
48  // The additional kSpxN is a result of the hash domain separator.
49  uint8_t mhash[kSpxForsMsgBytes];
50  uint64_t tree;
51  uint32_t idx_leaf;
52  HARDENED_RETURN_IF_ERROR(spx_hash_message(
53  sig, pk, msg_prefix_1, msg_prefix_1_len, msg_prefix_2, msg_prefix_2_len,
54  msg_prefix_3, msg_prefix_3_len, msg, msg_len, mhash, &tree, &idx_leaf));
55  sig += kSpxNWords;
56 
57  // Layer correctly defaults to 0, so no need to set_layer_addr.
58  spx_addr_tree_set(&wots_addr, tree);
59  spx_addr_keypair_set(&wots_addr, idx_leaf);
60 
61  fors_pk_from_sig(sig, mhash, &ctx, &wots_addr, root);
62  sig += kSpxForsWords;
63 
64  // For each subtree..
65  for (uint8_t i = 0; i < kSpxD; i++) {
66  spx_addr_layer_set(&tree_addr, i);
67  spx_addr_tree_set(&tree_addr, tree);
68 
69  spx_addr_subtree_copy(&wots_addr, &tree_addr);
70  spx_addr_keypair_set(&wots_addr, idx_leaf);
71 
72  spx_addr_keypair_copy(&wots_pk_addr, &wots_addr);
73 
74  // The WOTS public key is only correct if the signature was correct.
75  // Initially, root is the FORS pk, but on subsequent iterations it is
76  // the root of the subtree below the currently processed subtree.
77  uint32_t wots_pk[kSpxWotsWords];
78  wots_pk_from_sig(sig, root, &ctx, &wots_addr, wots_pk);
79  sig += kSpxWotsWords;
80 
81  // Compute the leaf node using the WOTS public key.
82  uint32_t leaf[kSpxNWords];
83  thash(wots_pk, kSpxWotsLen, &ctx, &wots_pk_addr, leaf);
84 
85  // Compute the root node of this subtree.
86  spx_utils_compute_root(leaf, idx_leaf, 0, sig, kSpxTreeHeight, &ctx,
87  &tree_addr, root);
88  sig += kSpxTreeHeight * kSpxNWords;
89 
90  // Update the indices for the next layer.
91  idx_leaf = (tree & ((1 << kSpxTreeHeight) - 1));
92  tree = tree >> kSpxTreeHeight;
93  }
94 
95  return kErrorOk;
96 }
97 
98 inline void spx_public_key_root(const uint32_t *pk, uint32_t *root) {
99  memcpy(root, pk + kSpxNWords, kSpxN);
100 }