Botan 3.11.0
Crypto and TLS for C&
sp_wots.cpp
Go to the documentation of this file.
1/*
2* WOTS+ - Winternitz One Time Signature Plus Scheme (FIPS 205, Section 5)
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_wots.h>
10
11#include <botan/internal/buffer_slicer.h>
12#include <botan/internal/buffer_stuffer.h>
13#include <botan/internal/sp_hash.h>
14
15namespace Botan {
16namespace {
17
18/**
19 * @brief FIPS 205, Algorithm 5: chain
20 *
21 * Computes a WOTS+ hash chain for @p steps steps beginning with value
22 * @p wots_chain_key at index @p start.
23 */
25 StrongSpan<const WotsNode> wots_chain_key,
26 WotsHashIndex start,
27 uint8_t steps,
28 Sphincs_Address& addr,
30 const Sphincs_Parameters& params) {
31 // Initialize out with the value at position 'start'.
32 std::copy(wots_chain_key.begin(), wots_chain_key.end(), out.begin());
33
34 // Iterate 'steps' calls to the hash function.
35 for(WotsHashIndex i = start; i < (start + steps) && i < params.w(); i++) {
36 addr.set_hash_address(i);
37 hashes.T(out, addr, out);
38 }
39}
40
41/**
42 * FIPS 205, Algorithm 4: base_2^b for WOTS+
43 *
44 * Interprets an array of bytes as integers in base w = 2^b.
45 * This only works when lg_w is a divisor of 8.
46 */
47void base_2_b(std::span<WotsHashIndex> output, std::span<const uint8_t> input, const Sphincs_Parameters& params) {
48 BOTAN_ASSERT_NOMSG(output.size() <= 8 * input.size() / params.log_w());
49
50 size_t input_offset = 0;
51 uint8_t current_byte = 0;
52 uint32_t remaining_bits_in_current_byte = 0;
53
54 for(auto& out : output) {
55 if(remaining_bits_in_current_byte == 0) {
56 current_byte = input[input_offset];
57 ++input_offset;
58 remaining_bits_in_current_byte = 8;
59 }
60 remaining_bits_in_current_byte -= params.log_w();
61 out = WotsHashIndex((current_byte >> remaining_bits_in_current_byte) & (params.w() - 1));
62 }
63}
64
65/**
66 * Computes the WOTS+ checksum over a message (in base_2^b).
67 * Corresponds to FIPS 205, Algorithm 7 or 8, Step 7.
68 */
69void wots_checksum(std::span<WotsHashIndex> output,
70 std::span<const WotsHashIndex> msg_base_w,
71 const Sphincs_Parameters& params) {
72 uint32_t csum = 0;
73
74 // Compute checksum.
75 for(auto wots_hash_index : msg_base_w) {
76 csum += params.w() - 1 - wots_hash_index.get();
77 }
78
79 // Convert checksum to base_w.
80 csum = csum << ((8 - ((params.wots_len_2() * params.log_w()) % 8)) % 8);
81
82 std::array<uint8_t, 4> csum_bytes{};
83 store_be(csum, csum_bytes.data());
84
85 const size_t csum_bytes_size = params.wots_checksum_bytes();
86 BOTAN_ASSERT_NOMSG(csum_bytes.size() >= csum_bytes_size);
87 base_2_b(output, std::span(csum_bytes).last(csum_bytes_size), params);
88}
89
90} // namespace
91
92std::vector<WotsHashIndex> chain_lengths(const SphincsTreeNode& msg, const Sphincs_Parameters& params) {
93 std::vector<WotsHashIndex> result(params.wots_len_1() + params.wots_len_2());
94
95 auto msg_base_w = std::span(result).first(params.wots_len_1());
96 auto checksum_base_w = std::span(result).last(params.wots_len_2());
97
98 base_2_b(msg_base_w, msg.get(), params);
99 wots_checksum(checksum_base_w, msg_base_w, params);
100
101 return result;
102}
103
106 Sphincs_Address& address,
107 const Sphincs_Parameters& params,
108 Sphincs_Hash_Functions& hashes) {
109 const std::vector<WotsHashIndex> lengths = chain_lengths(hashed_message, params);
110 WotsPublicKey pk_buffer(params.wots_len() * params.n());
111 BufferSlicer sig(signature);
112 BufferStuffer pk(pk_buffer);
113
114 for(WotsChainIndex i(0); i < params.wots_len(); i++) {
115 address.set_chain_address(i);
116
117 // params.w() can be one of {4, 8, 256}
118 const WotsHashIndex start_index = lengths[i.get()];
119 const uint8_t steps_to_take = static_cast<uint8_t>(params.w() - 1) - start_index.get();
120
121 chain(pk.next<WotsPublicKeyNode>(params.n()),
122 sig.take<WotsNode>(params.n()),
123 start_index,
124 steps_to_take,
125 address,
126 hashes,
127 params);
128 }
129
130 return pk_buffer;
131}
132
135 const SphincsSecretSeed& secret_seed,
136 TreeNodeIndex leaf_idx,
137 std::optional<TreeNodeIndex> sign_leaf_idx,
138 const std::vector<WotsHashIndex>& wots_steps,
139 Sphincs_Address& leaf_addr,
140 Sphincs_Address& pk_addr,
141 const Sphincs_Parameters& params,
142 Sphincs_Hash_Functions& hashes) {
143 // `wots_steps` are needed only if `sign_leaf_idx` is set
144 BOTAN_ASSERT_NOMSG(!sign_leaf_idx.has_value() || wots_steps.size() == params.wots_len());
146
147 const secure_vector<uint8_t> wots_sig;
148 WotsPublicKey wots_pk_buffer(params.wots_bytes());
149
150 BufferStuffer wots_pk(wots_pk_buffer);
151 BufferStuffer sig(sig_out);
152
153 leaf_addr.set_keypair_address(leaf_idx);
154 pk_addr.set_keypair_address(leaf_idx);
155
156 for(WotsChainIndex i(0); i < params.wots_len(); i++) {
157 // If the current leaf is part of the signature wots_k stores the chain index
158 // of the value necessary for the signature. Otherwise: nullopt (no signature)
159 const auto wots_k = [&]() -> std::optional<WotsHashIndex> {
160 if(sign_leaf_idx.has_value() && leaf_idx == sign_leaf_idx.value()) {
161 return wots_steps[i.get()];
162 } else {
163 return std::nullopt;
164 }
165 }();
166
167 // Start with the secret seed
168 leaf_addr.set_chain_address(i);
169 leaf_addr.set_hash_address(WotsHashIndex(0));
171
172 auto buffer_s = wots_pk.next<WotsNode>(params.n());
173
174 hashes.PRF(buffer_s, secret_seed, leaf_addr);
175
177
178 // Iterates down the WOTS chain
179 for(WotsHashIndex k(0);; k++) {
180 // Check if this is the value that needs to be saved as a part of the WOTS signature
181 if(wots_k.has_value() && k == wots_k.value()) {
182 std::copy(buffer_s.begin(), buffer_s.end(), sig.next<WotsNode>(params.n()).begin());
183 }
184
185 // Check if the top of the chain was hit
186 if(k == params.w() - 1) {
187 break;
188 }
189
190 // Iterate one step on the chain
191 leaf_addr.set_hash_address(k);
192
193 hashes.T(buffer_s, leaf_addr, buffer_s);
194 }
195 }
196
197 // Do the final thash to generate the public keys
198 hashes.T(leaf_out, pk_addr, wots_pk_buffer);
199}
200
201} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
std::span< const uint8_t > take(const size_t count)
Helper class to ease in-place marshalling of concatenated fixed-length values.
constexpr std::span< uint8_t > next(size_t bytes)
Sphincs_Address_Type get_type() const
Definition sp_address.h:134
Sphincs_Address & set_chain_address(WotsChainIndex chain)
Definition sp_address.h:81
Sphincs_Address & set_hash_address(WotsHashIndex hash)
Definition sp_address.h:91
Sphincs_Address & set_keypair_address(TreeNodeIndex keypair)
Definition sp_address.h:76
Sphincs_Address & set_type(Sphincs_Address_Type type)
Definition sp_address.h:71
void T(std::span< uint8_t > out, const Sphincs_Address &address, const BufferTs &... in)
Definition sp_hash.h:57
void PRF(StrongSpan< ForsLeafSecret > out, const SphincsSecretSeed &sk_seed, const Sphincs_Address &address)
Definition sp_hash.h:70
uint32_t wots_bytes() const
uint32_t wots_len_2() const
uint32_t wots_len_1() const
uint32_t wots_len() const
constexpr T & get() &
Definition strong_type.h:85
Strong< std::vector< uint8_t >, struct SphincsTreeNode_ > SphincsTreeNode
Either an XMSS or FORS tree node or leaf.
Definition sp_types.h:70
WotsPublicKey wots_public_key_from_signature(const SphincsTreeNode &hashed_message, StrongSpan< const WotsSignature > signature, Sphincs_Address &address, const Sphincs_Parameters &params, Sphincs_Hash_Functions &hashes)
FIPS 205, Algorithm 8: wots_pkFromSig.
Definition sp_wots.cpp:104
void wots_sign_and_pkgen(StrongSpan< WotsSignature > sig_out, StrongSpan< SphincsTreeNode > leaf_out, const SphincsSecretSeed &secret_seed, TreeNodeIndex leaf_idx, std::optional< TreeNodeIndex > sign_leaf_idx, const std::vector< WotsHashIndex > &wots_steps, Sphincs_Address &leaf_addr, Sphincs_Address &pk_addr, const Sphincs_Parameters &params, Sphincs_Hash_Functions &hashes)
FIPS 205, Algorithm 6 and 7: wots_pkGen and wots_sign.
Definition sp_wots.cpp:133
Strong< uint8_t, struct WotsHashIndex_, EnableArithmeticWithPlainNumber > WotsHashIndex
Index of a hash application inside a single WOTS chain (integers in "base_w").
Definition sp_types.h:98
Strong< secure_vector< uint8_t >, struct WotsNode_ > WotsNode
Start (or intermediate) node of a WOTS+ chain.
Definition sp_types.h:79
Strong< std::vector< uint8_t >, struct WotsPublicKey_ > WotsPublicKey
Definition sp_types.h:73
Strong< uint32_t, struct WotsChainIndex_ > WotsChainIndex
Index of a WOTS chain within a single usage of WOTS.
Definition sp_types.h:95
Strong< secure_vector< uint8_t >, struct SphincsSecretSeed_ > SphincsSecretSeed
Definition sp_types.h:61
Strong< std::vector< uint8_t >, struct WotsPublicKeyNode_ > WotsPublicKeyNode
End node of a WOTS+ chain (part of the WOTS+ public key).
Definition sp_types.h:76
Strong< uint32_t, struct TreeNodeIndex_, EnableArithmeticWithPlainNumber > TreeNodeIndex
Index of an individual node inside an XMSS or FORS tree.
Definition sp_types.h:92
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:68
std::vector< WotsHashIndex > chain_lengths(const SphincsTreeNode &msg, const Sphincs_Parameters &params)
Definition sp_wots.cpp:92
constexpr auto store_be(ParamTs &&... params)
Definition loadstor.h:745