Software APIs
fors.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/fors.h
7 
8 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/fors.h"
9 
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/thash.h"
13 #include "sw/device/silicon_creator/lib/sigverify/sphincsplus/utils.h"
14 
15 /**
16  * Get the leaf value from the FORS secret key.
17  *
18  * @param sk Input secret key (`kSpxN` bytes).
19  * @param ctx Context object.
20  * @param fors_leaf_addr Leaf address.
21  * @param[out] leaf Resulting leaf (`kSpxNWords` words).
22  */
23 static void fors_sk_to_leaf(const uint32_t *sk, const spx_ctx_t *ctx,
24  spx_addr_t *fors_leaf_addr, uint32_t *leaf) {
25  return thash(sk, /*inblocks=*/1, ctx, fors_leaf_addr, leaf);
26 }
27 
28 /**
29  * Interprets m as `kSpxForsHeight`-bit unsigned integers.
30  *
31  * Assumes m contains at least kSpxForsHeight * kSpxForsTrees bits.
32  * Assumes indices has space for kSpxForsTrees integers.
33  *
34  * @param m Input message.
35  * @param[out] indices Buffer for indices.
36  */
37 static void message_to_indices(const uint8_t *m, uint32_t *indices) {
38  size_t offset = 0;
39  for (size_t i = 0; i < kSpxForsTrees; i++) {
40  indices[i] = 0;
41  for (size_t j = 0; j < kSpxForsHeight; j++) {
42  indices[i] ^= ((m[offset >> 3] >> (~offset & 0x7u)) & 0x1u)
43  << (kSpxForsHeight - 1 - j);
44  offset++;
45  }
46  }
47 }
48 
49 void fors_pk_from_sig(const uint32_t *sig, const uint8_t *m,
50  const spx_ctx_t *ctx, const spx_addr_t *fors_addr,
51  uint32_t *pk) {
52  // Initialize the FORS tree address.
53  spx_addr_t fors_tree_addr = {.addr = {0}};
54  spx_addr_keypair_copy(&fors_tree_addr, fors_addr);
55  spx_addr_type_set(&fors_tree_addr, kSpxAddrTypeForsTree);
56 
57  // Initialize the FORS public key address.
58  spx_addr_t fors_pk_addr = {.addr = {0}};
59  spx_addr_keypair_copy(&fors_pk_addr, fors_addr);
60  spx_addr_type_set(&fors_pk_addr, kSpxAddrTypeForsPk);
61 
62  uint32_t indices[kSpxForsTrees];
63  message_to_indices(m, indices);
64 
65  uint32_t roots[kSpxForsTrees * kSpxNWords];
66  for (size_t i = 0; i < kSpxForsTrees; i++) {
67  uint32_t idx_offset = i * (1 << kSpxForsHeight);
68 
69  spx_addr_tree_height_set(&fors_tree_addr, 0);
70  spx_addr_tree_index_set(&fors_tree_addr, indices[i] + idx_offset);
71 
72  // Derive the leaf from the included secret key part.
73  uint32_t leaf[kSpxNWords];
74  fors_sk_to_leaf(sig, ctx, &fors_tree_addr, leaf);
75  sig += kSpxNWords;
76 
77  // Derive the corresponding root node of this tree.
78  uint32_t *root = &roots[i * kSpxNWords];
79  spx_utils_compute_root(leaf, indices[i], idx_offset, sig, kSpxForsHeight,
80  ctx, &fors_tree_addr, root);
81  sig += kSpxNWords * kSpxForsHeight;
82  }
83 
84  // Hash horizontally across all tree roots to derive the public key.
85  thash(roots, kSpxForsTrees, ctx, &fors_pk_addr, pk);
86 }