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