Botan 3.4.0
Crypto and TLS for C&
sp_treehash.cpp
Go to the documentation of this file.
1/*
2* Sphincs+ treehash logic
3* (C) 2023 Jack Lloyd
4* 2023 Fabian Albert, René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7**/
8
9#include <botan/internal/sp_treehash.h>
10
11#include <botan/internal/sp_address.h>
12#include <botan/internal/sp_hash.h>
13#include <botan/internal/stl_util.h>
14
15namespace Botan {
16
17namespace {
18
19void copy_into(std::span<uint8_t> out, std::span<const uint8_t> in) {
20 BOTAN_ASSERT_NOMSG(in.size() == out.size());
21 std::copy(in.begin(), in.end(), out.begin());
22}
23
24} // namespace
25
28 const Sphincs_Parameters& params,
30 std::optional<TreeNodeIndex> leaf_idx,
31 uint32_t idx_offset,
32 uint32_t total_tree_height,
33 const GenerateLeafFunction& gen_leaf,
34 Sphincs_Address& tree_address) {
35 BOTAN_ASSERT_NOMSG(out_root.size() == params.n());
36 BOTAN_ASSERT_NOMSG(out_auth_path.size() == params.n() * total_tree_height);
37
38 const TreeNodeIndex max_idx(uint32_t((1 << total_tree_height) - 1));
39
40 std::vector<uint8_t> stack(total_tree_height * params.n());
41 SphincsTreeNode current_node(params.n()); // Current logical node
42
43 /* Traverse the tree from the left-most leaf, matching siblings and up until
44 * the root (Post-order traversal). Collect the adjacent nodes (A) to build
45 * the authentication path (X) along the way.
46 *
47 * 7R
48 * / \
49 * 3X 6A
50 * / \ / \
51 * 1X 2A 4 5
52 */
53 for(TreeNodeIndex idx(0); true; ++idx) {
54 tree_address.set_tree_height(TreeLayerIndex(0));
55 gen_leaf(current_node, idx + idx_offset);
56
57 // Now combine the freshly generated right node with previously generated
58 // left ones
59 uint32_t internal_idx_offset = idx_offset;
60 TreeNodeIndex internal_idx = idx;
61 auto internal_leaf = leaf_idx;
62
63 for(TreeLayerIndex h(0); true; ++h) {
64 // Check if we hit the top of the tree
65 if(h.get() == total_tree_height) {
66 copy_into(out_root, current_node);
67 return;
68 }
69
70 // Check if the node we have is a part of the authentication path; if
71 // it is, write it out. The XOR sum of both nodes (at internal_idx and internal_leaf)
72 // is 1 iff they have the same parent node in the FORS tree
73 if(internal_leaf.has_value() && (internal_idx ^ internal_leaf.value()) == 0x01U) {
74 auto auth_path_location = out_auth_path.get().subspan(h.get() * params.n(), params.n());
75 copy_into(auth_path_location, current_node);
76 }
77
78 // At this point we know that we'll need to use the stack. Get a
79 // reference to the correct location.
80 auto stack_location = std::span(stack).subspan(h.get() * params.n(), params.n());
81
82 // Check if we're at a left child; if so, stop going up the stack
83 // Exception: if we've reached the end of the tree, keep on going (so
84 // we combine the last 4 nodes into the one root node in two more
85 // iterations)
86 if((internal_idx & 1) == 0U && idx < max_idx) {
87 // We've hit a left child; save the current for when we get the
88 // corresponding right child.
89 copy_into(stack_location, current_node);
90 break;
91 }
92
93 // Ok, we're at a right node. Now combine the left and right logical
94 // nodes together.
95
96 // Set the address of the node we're creating.
97 internal_idx_offset /= 2;
98 tree_address.set_tree_height(h + 1);
99 tree_address.set_tree_index(internal_idx / 2 + internal_idx_offset);
100
101 hashes.T(current_node, tree_address, stack_location, current_node);
102
103 internal_idx /= 2;
104 if(internal_leaf.has_value()) {
105 internal_leaf.value() /= 2;
106 }
107 }
108 }
109}
110
112 const Sphincs_Parameters& params,
114 const SphincsTreeNode& leaf,
115 TreeNodeIndex leaf_idx,
116 uint32_t idx_offset,
118 uint32_t total_tree_height,
119 Sphincs_Address& tree_address) {
120 BOTAN_ASSERT_NOMSG(out.size() == params.n());
121 BOTAN_ASSERT_NOMSG(authentication_path.size() == params.n() * total_tree_height);
122 BOTAN_ASSERT_NOMSG(leaf.size() == params.n());
123
124 // Use the `out` parameter as intermediate buffer for left/right nodes
125 // while traversing the tree.
126 copy_into(out, leaf);
127
128 // Views into either `auth_path` or `out` depending on the tree location.
131
132 BufferSlicer auth_path(authentication_path);
133
134 // The leaf is put in the left or right buffer, depending on its indexes parity.
135 // Same for the first node of the authentication path
136
137 for(TreeLayerIndex i(0); i < total_tree_height; i++) {
138 // The input of the hash function takes the current node and the node
139 // given in the authentication path. If the current node is a right node
140 // in the tree (i.e. its leaf index is uneven) the hash function inputs
141 // must be swapped.
142 left = out;
143 right = auth_path.take<SphincsTreeNode>(params.n());
144
145 if((leaf_idx & 1) == 1U) {
146 std::swap(left, right);
147 }
148
149 leaf_idx /= 2;
150 idx_offset /= 2;
151 tree_address.set_tree_height(i + 1).set_tree_index(leaf_idx + idx_offset);
152
153 hashes.T(out, tree_address, left, right);
154 }
155
156 BOTAN_ASSERT_NOMSG(auth_path.empty());
157}
158
159} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
bool empty() const
Definition stl_util.h:187
std::span< const uint8_t > take(const size_t count)
Definition stl_util.h:156
Sphincs_Address & set_tree_height(TreeLayerIndex tree_height)
Definition sp_address.h:91
Sphincs_Address & set_tree_index(TreeNodeIndex tree_index)
Definition sp_address.h:96
void T(std::span< uint8_t > out, const Sphincs_Address &address, BufferTs &&... in)
Definition sp_hash.h:56
underlying_span get() const
decltype(auto) size() const noexcept(noexcept(this->m_span.size()))
std::function< void(StrongSpan< SphincsTreeNode >, TreeNodeIndex)> GenerateLeafFunction
Definition sp_treehash.h:25
Strong< uint32_t, struct TreeLayerIndex_, EnableArithmeticWithPlainNumber > TreeLayerIndex
Index of the layer within a FORS/XMSS tree.
Definition sp_types.h:69
void treehash(StrongSpan< SphincsTreeNode > out_root, StrongSpan< SphincsAuthenticationPath > out_auth_path, const Sphincs_Parameters &params, Sphincs_Hash_Functions &hashes, std::optional< TreeNodeIndex > leaf_idx, uint32_t idx_offset, uint32_t total_tree_height, const GenerateLeafFunction &gen_leaf, Sphincs_Address &tree_address)
void compute_root(StrongSpan< SphincsTreeNode > out, const Sphincs_Parameters &params, Sphincs_Hash_Functions &hashes, const SphincsTreeNode &leaf, TreeNodeIndex leaf_idx, uint32_t idx_offset, StrongSpan< const SphincsAuthenticationPath > authentication_path, uint32_t total_tree_height, Sphincs_Address &tree_address)