Botan 3.9.0
Crypto and TLS for C&
sp_parameters.cpp
Go to the documentation of this file.
1/*
2 * SLH-DSA Parameters
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/sp_parameters.h>
10
11#include <botan/assert.h>
12#include <botan/concepts.h>
13#include <botan/exceptn.h>
14#include <botan/internal/bit_ops.h>
15#include <botan/internal/fmt.h>
16
17#include <cmath>
18
19namespace Botan {
20
21namespace {
22/// @returns pair: (parameter set, hash type)
23std::pair<Sphincs_Parameter_Set, Sphincs_Hash_Type> set_and_hash_from_name(std::string_view name) {
24 // SPHINCS+ Round 3.1 instances
25 if(name == "SphincsPlus-sha2-128s-r3.1") {
27 }
28 if(name == "SphincsPlus-sha2-128f-r3.1") {
30 }
31 if(name == "SphincsPlus-sha2-192s-r3.1") {
33 }
34 if(name == "SphincsPlus-sha2-192f-r3.1") {
36 }
37 if(name == "SphincsPlus-sha2-256s-r3.1") {
39 }
40 if(name == "SphincsPlus-sha2-256f-r3.1") {
42 }
43
44 if(name == "SphincsPlus-shake-128s-r3.1") {
46 }
47 if(name == "SphincsPlus-shake-128f-r3.1") {
49 }
50 if(name == "SphincsPlus-shake-192s-r3.1") {
52 }
53 if(name == "SphincsPlus-shake-192f-r3.1") {
55 }
56 if(name == "SphincsPlus-shake-256s-r3.1") {
58 }
59 if(name == "SphincsPlus-shake-256f-r3.1") {
61 }
62
63 if(name == "SphincsPlus-haraka-128s-r3.1") {
65 }
66 if(name == "SphincsPlus-haraka-128f-r3.1") {
68 }
69 if(name == "SphincsPlus-haraka-192s-r3.1") {
71 }
72 if(name == "SphincsPlus-haraka-192f-r3.1") {
74 }
75 if(name == "SphincsPlus-haraka-256s-r3.1") {
77 }
78 if(name == "SphincsPlus-haraka-256f-r3.1") {
80 }
81
82 // SLH-DSA instances WITHOUT prehash mode
83 if(name == "SLH-DSA-SHA2-128s") {
85 }
86 if(name == "SLH-DSA-SHA2-128f") {
88 }
89 if(name == "SLH-DSA-SHA2-192s") {
91 }
92 if(name == "SLH-DSA-SHA2-192f") {
94 }
95 if(name == "SLH-DSA-SHA2-256s") {
97 }
98 if(name == "SLH-DSA-SHA2-256f") {
100 }
101
102 if(name == "SLH-DSA-SHAKE-128s") {
104 }
105 if(name == "SLH-DSA-SHAKE-128f") {
107 }
108 if(name == "SLH-DSA-SHAKE-192s") {
110 }
111 if(name == "SLH-DSA-SHAKE-192f") {
113 }
114 if(name == "SLH-DSA-SHAKE-256s") {
116 }
117 if(name == "SLH-DSA-SHAKE-256f") {
119 }
120
121 // SLH-DSA instances WITH prehash mode
122 if(name == "Hash-SLH-DSA-SHA2-128s-with-SHA256") {
124 }
125 if(name == "Hash-SLH-DSA-SHA2-128f-with-SHA256") {
127 }
128 if(name == "Hash-SLH-DSA-SHA2-192s-with-SHA512") {
130 }
131 if(name == "Hash-SLH-DSA-SHA2-192f-with-SHA512") {
133 }
134 if(name == "Hash-SLH-DSA-SHA2-256s-with-SHA512") {
136 }
137 if(name == "Hash-SLH-DSA-SHA2-256f-with-SHA512") {
139 }
140
141 if(name == "Hash-SLH-DSA-SHAKE-128s-with-SHAKE128") {
143 }
144 if(name == "Hash-SLH-DSA-SHAKE-128f-with-SHAKE128") {
146 }
147 if(name == "Hash-SLH-DSA-SHAKE-192s-with-SHAKE256") {
149 }
150 if(name == "Hash-SLH-DSA-SHAKE-192f-with-SHAKE256") {
152 }
153 if(name == "Hash-SLH-DSA-SHAKE-256s-with-SHAKE256") {
155 }
156 if(name == "Hash-SLH-DSA-SHAKE-256f-with-SHAKE256") {
158 }
159
160 throw Lookup_Error(fmt("No SLH-DSA (or SPHINCS+) parameter supported for: {}", name));
161}
162
163std::string name_from_set_and_hash(Sphincs_Parameter_Set set, Sphincs_Hash_Type hash) {
164 if(hash == Sphincs_Hash_Type::Sha256) {
165 switch(set) {
167 return "SphincsPlus-sha2-128s-r3.1";
169 return "SphincsPlus-sha2-128f-r3.1";
171 return "SphincsPlus-sha2-192s-r3.1";
173 return "SphincsPlus-sha2-192f-r3.1";
175 return "SphincsPlus-sha2-256s-r3.1";
177 return "SphincsPlus-sha2-256f-r3.1";
178
180 return "SLH-DSA-SHA2-128s";
182 return "SLH-DSA-SHA2-128f";
184 return "SLH-DSA-SHA2-192s";
186 return "SLH-DSA-SHA2-192f";
188 return "SLH-DSA-SHA2-256s";
190 return "SLH-DSA-SHA2-256f";
191 }
192 }
193
194 if(hash == Sphincs_Hash_Type::Shake256) {
195 switch(set) {
197 return "SphincsPlus-shake-128s-r3.1";
199 return "SphincsPlus-shake-128f-r3.1";
201 return "SphincsPlus-shake-192s-r3.1";
203 return "SphincsPlus-shake-192f-r3.1";
205 return "SphincsPlus-shake-256s-r3.1";
207 return "SphincsPlus-shake-256f-r3.1";
208
210 return "SLH-DSA-SHAKE-128s";
212 return "SLH-DSA-SHAKE-128f";
214 return "SLH-DSA-SHAKE-192s";
216 return "SLH-DSA-SHAKE-192f";
218 return "SLH-DSA-SHAKE-256s";
220 return "SLH-DSA-SHAKE-256f";
221 }
222 }
223
224 if(hash == Sphincs_Hash_Type::Haraka) {
225 switch(set) {
227 return "SphincsPlus-haraka-128s-r3.1";
229 return "SphincsPlus-haraka-128f-r3.1";
231 return "SphincsPlus-haraka-192s-r3.1";
233 return "SphincsPlus-haraka-192f-r3.1";
235 return "SphincsPlus-haraka-256s-r3.1";
237 return "SphincsPlus-haraka-256f-r3.1";
238
245 throw Invalid_Argument("SLH-DSA does not support Haraka");
246 }
247 }
248 throw Invalid_Argument("Cannot serialize invalid parameter combination");
249}
250
251constexpr bool is_slh_dsa_set(Sphincs_Parameter_Set set) {
252 switch(set) {
259 return true;
266 return false;
267 }
269}
270
271} // namespace
272
273Sphincs_Parameters::Sphincs_Parameters(Sphincs_Parameter_Set set,
274 Sphincs_Hash_Type hash_type,
275 uint32_t n,
276 uint32_t h,
277 uint32_t d,
278 uint32_t a,
279 uint32_t k,
280 uint32_t w,
281 uint32_t bitsec) :
282 m_set(set), m_hash_type(hash_type), m_n(n), m_h(h), m_d(d), m_a(a), m_k(k), m_w(w), m_bitsec(bitsec) {
283 BOTAN_ARG_CHECK(!(hash_type == Sphincs_Hash_Type::Haraka && is_slh_dsa_set(set)),
284 "Haraka is not available for SLH-DSA");
285 BOTAN_ARG_CHECK(w == 4 || w == 16 || w == 256, "Winternitz parameter must be one of 4, 16, 256");
286 BOTAN_ARG_CHECK(n == 16 || n == 24 || n == 32, "n must be one of 16, 24, 32");
287 BOTAN_ARG_CHECK(m_d > 0, "d must be greater than zero");
288
289 m_xmss_tree_height = m_h / m_d;
290 m_lg_w = ceil_log2(m_w);
291
292 // base_2^b algorithm (Fips 205, Algorithm 4) only works
293 // when m_log_w is a divisor of 8.
294 BOTAN_ASSERT_NOMSG(m_lg_w <= 8 && 8 % m_lg_w == 0);
295
296 // # Winternitz blocks of the message (len_1 of FIPS 205, Algorithm 1)
297 m_wots_len1 = (m_n * 8) / m_lg_w;
298
299 // # Winternitz blocks of the checksum (output of FIPS 205 Algorithm 1)
300 m_wots_len2 = ceil_log2(m_wots_len1 * (m_w - 1)) / m_lg_w + 1;
301
302 // # Winternitz blocks in the signature (len of FIPS 205, Equation 5.4)
303 m_wots_len = m_wots_len1 + m_wots_len2;
304
305 // byte length of WOTS+ signature as well as public key
306 m_wots_bytes = m_wots_len * m_n;
307
308 // # of bytes the WOTS+ checksum consists of
309 m_wots_checksum_bytes = ceil_tobytes(m_wots_len2 * m_lg_w);
310
311 m_fors_sig_bytes = (m_a + 1) * m_k * m_n;
312
313 // byte length of the FORS input message
314 m_fors_message_bytes = ceil_tobytes(m_k * m_a);
315
316 m_xmss_sig_bytes = m_wots_bytes + m_xmss_tree_height * m_n;
317 m_ht_sig_bytes = m_d * m_xmss_sig_bytes;
318 m_sp_sig_bytes = m_n /* random */ + m_fors_sig_bytes + m_ht_sig_bytes;
319
320 m_tree_digest_bytes = ceil_tobytes(m_h - m_xmss_tree_height);
321 m_leaf_digest_bytes = ceil_tobytes(m_xmss_tree_height);
322 m_h_msg_digest_bytes = m_fors_message_bytes + m_tree_digest_bytes + m_leaf_digest_bytes;
323}
324
326 [[maybe_unused]] const bool is_slh_dsa = is_slh_dsa_set(m_set);
327#ifdef BOTAN_HAS_SLH_DSA_WITH_SHA2
328 if(is_slh_dsa && m_hash_type == Sphincs_Hash_Type::Sha256) {
329 return true;
330 }
331#endif
332#ifdef BOTAN_HAS_SLH_DSA_WITH_SHAKE
333 if(is_slh_dsa && m_hash_type == Sphincs_Hash_Type::Shake256) {
334 return true;
335 }
336#endif
337#ifdef BOTAN_HAS_SPHINCS_PLUS_WITH_SHA2
338 if(!is_slh_dsa && m_hash_type == Sphincs_Hash_Type::Sha256) {
339 return true;
340 }
341#endif
342#ifdef BOTAN_HAS_SPHINCS_PLUS_WITH_SHAKE
343 if(!is_slh_dsa && m_hash_type == Sphincs_Hash_Type::Shake256) {
344 return true;
345 }
346#endif
347 return false;
348}
349
350Sphincs_Parameters Sphincs_Parameters::create(
351 Sphincs_Parameter_Set set, Sphincs_Hash_Type hash /*, SlhDsaInputMode input_mode [TODO: prehash mode]*/) {
352 // See FIPS 205, Table 2
353 switch(set) {
356 return Sphincs_Parameters(set, hash, 16, 63, 7, 12, 14, 16, 133);
359 return Sphincs_Parameters(set, hash, 16, 66, 22, 6, 33, 16, 128);
360
363 return Sphincs_Parameters(set, hash, 24, 63, 7, 14, 17, 16, 193);
366 return Sphincs_Parameters(set, hash, 24, 66, 22, 8, 33, 16, 194);
367
370 return Sphincs_Parameters(set, hash, 32, 64, 8, 14, 22, 16, 255);
373 return Sphincs_Parameters(set, hash, 32, 68, 17, 9, 35, 16, 255);
374 }
376}
377
378Sphincs_Parameters Sphincs_Parameters::create(std::string_view name) {
379 auto [param_set, hash_type] = set_and_hash_from_name(name);
380 return Sphincs_Parameters::create(param_set, hash_type);
381}
382
384 return is_slh_dsa_set(m_set);
385}
386
387std::string Sphincs_Parameters::hash_name() const {
388 switch(m_hash_type) {
390 return "SHA-256";
392 return fmt("SHAKE-256({})", 8 * n());
394 return "Haraka";
395 }
397}
398
399std::string Sphincs_Parameters::to_string() const {
400 return name_from_set_and_hash(parameter_set(), hash_type());
401}
402
403Sphincs_Parameters Sphincs_Parameters::create(const OID& oid) {
405}
406
410
414
415} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
#define BOTAN_ASSERT_UNREACHABLE()
Definition assert.h:163
std::string to_formatted_string() const
Definition asn1_oid.cpp:139
static OID from_string(std::string_view str)
Definition asn1_oid.cpp:86
Sphincs_Parameter_Set parameter_set() const
std::string to_string() const
AlgorithmIdentifier algorithm_identifier() const
std::string hash_name() const
Sphincs_Hash_Type hash_type() const
static Sphincs_Parameters create(Sphincs_Parameter_Set set, Sphincs_Hash_Type hash)
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
Sphincs_Parameter_Set
Sphincs_Hash_Type
@ Haraka
Haraka is currently not supported.
constexpr uint8_t ceil_log2(T x)
Definition bit_ops.h:120
BOTAN_FORCE_INLINE constexpr T ceil_tobytes(T bits)
Definition bit_ops.h:155