Botan 3.6.1
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/concepts.h>
12#include <botan/exceptn.h>
13#include <botan/internal/bit_ops.h>
14#include <botan/internal/fmt.h>
15
16#include <cmath>
17
18namespace Botan {
19
20namespace {
21/// @returns pair: (parameter set, hash type)
22std::pair<Sphincs_Parameter_Set, Sphincs_Hash_Type> set_and_hash_from_name(std::string_view name) {
23 // SPHINCS+ Round 3.1 instances
24 if(name == "SphincsPlus-sha2-128s-r3.1") {
26 }
27 if(name == "SphincsPlus-sha2-128f-r3.1") {
29 }
30 if(name == "SphincsPlus-sha2-192s-r3.1") {
32 }
33 if(name == "SphincsPlus-sha2-192f-r3.1") {
35 }
36 if(name == "SphincsPlus-sha2-256s-r3.1") {
38 }
39 if(name == "SphincsPlus-sha2-256f-r3.1") {
41 }
42
43 if(name == "SphincsPlus-shake-128s-r3.1") {
45 }
46 if(name == "SphincsPlus-shake-128f-r3.1") {
48 }
49 if(name == "SphincsPlus-shake-192s-r3.1") {
51 }
52 if(name == "SphincsPlus-shake-192f-r3.1") {
54 }
55 if(name == "SphincsPlus-shake-256s-r3.1") {
57 }
58 if(name == "SphincsPlus-shake-256f-r3.1") {
60 }
61
62 if(name == "SphincsPlus-haraka-128s-r3.1") {
64 }
65 if(name == "SphincsPlus-haraka-128f-r3.1") {
67 }
68 if(name == "SphincsPlus-haraka-192s-r3.1") {
70 }
71 if(name == "SphincsPlus-haraka-192f-r3.1") {
73 }
74 if(name == "SphincsPlus-haraka-256s-r3.1") {
76 }
77 if(name == "SphincsPlus-haraka-256f-r3.1") {
79 }
80
81 // SLH-DSA instances WITHOUT prehash mode
82 if(name == "SLH-DSA-SHA2-128s") {
84 }
85 if(name == "SLH-DSA-SHA2-128f") {
87 }
88 if(name == "SLH-DSA-SHA2-192s") {
90 }
91 if(name == "SLH-DSA-SHA2-192f") {
93 }
94 if(name == "SLH-DSA-SHA2-256s") {
96 }
97 if(name == "SLH-DSA-SHA2-256f") {
99 }
100
101 if(name == "SLH-DSA-SHAKE-128s") {
103 }
104 if(name == "SLH-DSA-SHAKE-128f") {
106 }
107 if(name == "SLH-DSA-SHAKE-192s") {
109 }
110 if(name == "SLH-DSA-SHAKE-192f") {
112 }
113 if(name == "SLH-DSA-SHAKE-256s") {
115 }
116 if(name == "SLH-DSA-SHAKE-256f") {
118 }
119
120 // SLH-DSA instances WITH prehash mode
121 if(name == "Hash-SLH-DSA-SHA2-128s-with-SHA256") {
123 }
124 if(name == "Hash-SLH-DSA-SHA2-128f-with-SHA256") {
126 }
127 if(name == "Hash-SLH-DSA-SHA2-192s-with-SHA512") {
129 }
130 if(name == "Hash-SLH-DSA-SHA2-192f-with-SHA512") {
132 }
133 if(name == "Hash-SLH-DSA-SHA2-256s-with-SHA512") {
135 }
136 if(name == "Hash-SLH-DSA-SHA2-256f-with-SHA512") {
138 }
139
140 if(name == "Hash-SLH-DSA-SHAKE-128s-with-SHAKE128") {
142 }
143 if(name == "Hash-SLH-DSA-SHAKE-128f-with-SHAKE128") {
145 }
146 if(name == "Hash-SLH-DSA-SHAKE-192s-with-SHAKE256") {
148 }
149 if(name == "Hash-SLH-DSA-SHAKE-192f-with-SHAKE256") {
151 }
152 if(name == "Hash-SLH-DSA-SHAKE-256s-with-SHAKE256") {
154 }
155 if(name == "Hash-SLH-DSA-SHAKE-256f-with-SHAKE256") {
157 }
158
159 throw Lookup_Error(fmt("No SLH-DSA (or SPHINCS+) parameter supported for: {}", name));
160}
161
162std::string name_from_set_and_hash(Sphincs_Parameter_Set set, Sphincs_Hash_Type hash) {
163 if(hash == Sphincs_Hash_Type::Sha256) {
164 switch(set) {
166 return "SphincsPlus-sha2-128s-r3.1";
168 return "SphincsPlus-sha2-128f-r3.1";
170 return "SphincsPlus-sha2-192s-r3.1";
172 return "SphincsPlus-sha2-192f-r3.1";
174 return "SphincsPlus-sha2-256s-r3.1";
176 return "SphincsPlus-sha2-256f-r3.1";
177
179 return "SLH-DSA-SHA2-128s";
181 return "SLH-DSA-SHA2-128f";
183 return "SLH-DSA-SHA2-192s";
185 return "SLH-DSA-SHA2-192f";
187 return "SLH-DSA-SHA2-256s";
189 return "SLH-DSA-SHA2-256f";
190 }
191 }
192
193 if(hash == Sphincs_Hash_Type::Shake256) {
194 switch(set) {
196 return "SphincsPlus-shake-128s-r3.1";
198 return "SphincsPlus-shake-128f-r3.1";
200 return "SphincsPlus-shake-192s-r3.1";
202 return "SphincsPlus-shake-192f-r3.1";
204 return "SphincsPlus-shake-256s-r3.1";
206 return "SphincsPlus-shake-256f-r3.1";
207
209 return "SLH-DSA-SHAKE-128s";
211 return "SLH-DSA-SHAKE-128f";
213 return "SLH-DSA-SHAKE-192s";
215 return "SLH-DSA-SHAKE-192f";
217 return "SLH-DSA-SHAKE-256s";
219 return "SLH-DSA-SHAKE-256f";
220 }
221 }
222
223 if(hash == Sphincs_Hash_Type::Haraka) {
224 switch(set) {
226 return "SphincsPlus-haraka-128s-r3.1";
228 return "SphincsPlus-haraka-128f-r3.1";
230 return "SphincsPlus-haraka-192s-r3.1";
232 return "SphincsPlus-haraka-192f-r3.1";
234 return "SphincsPlus-haraka-256s-r3.1";
236 return "SphincsPlus-haraka-256f-r3.1";
237
244 throw Invalid_Argument("SLH-DSA does not support Haraka");
245 }
246 }
247 throw Invalid_Argument("Cannot serialize invalid parameter combination");
248}
249
250constexpr bool is_slh_dsa_set(Sphincs_Parameter_Set set) {
251 switch(set) {
258 return true;
265 return false;
266 }
268}
269
270} // namespace
271
272Sphincs_Parameters::Sphincs_Parameters(Sphincs_Parameter_Set set,
273 Sphincs_Hash_Type hash_type,
274 uint32_t n,
275 uint32_t h,
276 uint32_t d,
277 uint32_t a,
278 uint32_t k,
279 uint32_t w,
280 uint32_t bitsec) :
281 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) {
282 BOTAN_ARG_CHECK(!(hash_type == Sphincs_Hash_Type::Haraka && is_slh_dsa_set(set)),
283 "Haraka is not available for SLH-DSA");
284 BOTAN_ARG_CHECK(w == 4 || w == 16 || w == 256, "Winternitz parameter must be one of 4, 16, 256");
285 BOTAN_ARG_CHECK(n == 16 || n == 24 || n == 32, "n must be one of 16, 24, 32");
286 BOTAN_ARG_CHECK(m_d > 0, "d must be greater than zero");
287
288 m_xmss_tree_height = m_h / m_d;
289 m_lg_w = ceil_log2(m_w);
290
291 // base_2^b algorithm (Fips 205, Algorithm 4) only works
292 // when m_log_w is a divisor of 8.
293 BOTAN_ASSERT_NOMSG(m_lg_w <= 8 && 8 % m_lg_w == 0);
294
295 // # Winternitz blocks of the message (len_1 of FIPS 205, Algorithm 1)
296 m_wots_len1 = (m_n * 8) / m_lg_w;
297
298 // # Winternitz blocks of the checksum (output of FIPS 205 Algorithm 1)
299 m_wots_len2 = ceil_log2(m_wots_len1 * (m_w - 1)) / m_lg_w + 1;
300
301 // # Winternitz blocks in the signature (len of FIPS 205, Equation 5.4)
302 m_wots_len = m_wots_len1 + m_wots_len2;
303
304 // byte length of WOTS+ signature as well as public key
305 m_wots_bytes = m_wots_len * m_n;
306
307 // # of bytes the WOTS+ checksum consists of
308 m_wots_checksum_bytes = ceil_tobytes(m_wots_len2 * m_lg_w);
309
310 m_fors_sig_bytes = (m_a + 1) * m_k * m_n;
311
312 // byte length of the FORS input message
313 m_fors_message_bytes = ceil_tobytes(m_k * m_a);
314
315 m_xmss_sig_bytes = m_wots_bytes + m_xmss_tree_height * m_n;
316 m_ht_sig_bytes = m_d * m_xmss_sig_bytes;
317 m_sp_sig_bytes = m_n /* random */ + m_fors_sig_bytes + m_ht_sig_bytes;
318
319 m_tree_digest_bytes = ceil_tobytes(m_h - m_xmss_tree_height);
320 m_leaf_digest_bytes = ceil_tobytes(m_xmss_tree_height);
321 m_h_msg_digest_bytes = m_fors_message_bytes + m_tree_digest_bytes + m_leaf_digest_bytes;
322}
323
324bool Sphincs_Parameters::is_available() const {
325 [[maybe_unused]] const bool is_slh_dsa = is_slh_dsa_set(m_set);
326#ifdef BOTAN_HAS_SLH_DSA_WITH_SHA2
327 if(is_slh_dsa && m_hash_type == Sphincs_Hash_Type::Sha256) {
328 return true;
329 }
330#endif
331#ifdef BOTAN_HAS_SLH_DSA_WITH_SHAKE
332 if(is_slh_dsa && m_hash_type == Sphincs_Hash_Type::Shake256) {
333 return true;
334 }
335#endif
336#ifdef BOTAN_HAS_SPHINCS_PLUS_WITH_SHA2
337 if(!is_slh_dsa && m_hash_type == Sphincs_Hash_Type::Sha256) {
338 return true;
339 }
340#endif
341#ifdef BOTAN_HAS_SPHINCS_PLUS_WITH_SHAKE
342 if(!is_slh_dsa && m_hash_type == Sphincs_Hash_Type::Shake256) {
343 return true;
344 }
345#endif
346 return false;
347}
348
349Sphincs_Parameters Sphincs_Parameters::create(
350 Sphincs_Parameter_Set set, Sphincs_Hash_Type hash /*, SlhDsaInputMode input_mode [TODO: prehash mode]*/) {
351 // See FIPS 205, Table 2
352 switch(set) {
353 case Sphincs_Parameter_Set::Sphincs128Small:
354 case Sphincs_Parameter_Set::SLHDSA128Small:
355 return Sphincs_Parameters(set, hash, 16, 63, 7, 12, 14, 16, 133);
356 case Sphincs_Parameter_Set::Sphincs128Fast:
357 case Sphincs_Parameter_Set::SLHDSA128Fast:
358 return Sphincs_Parameters(set, hash, 16, 66, 22, 6, 33, 16, 128);
359
360 case Sphincs_Parameter_Set::Sphincs192Small:
361 case Sphincs_Parameter_Set::SLHDSA192Small:
362 return Sphincs_Parameters(set, hash, 24, 63, 7, 14, 17, 16, 193);
363 case Sphincs_Parameter_Set::Sphincs192Fast:
364 case Sphincs_Parameter_Set::SLHDSA192Fast:
365 return Sphincs_Parameters(set, hash, 24, 66, 22, 8, 33, 16, 194);
366
367 case Sphincs_Parameter_Set::Sphincs256Small:
368 case Sphincs_Parameter_Set::SLHDSA256Small:
369 return Sphincs_Parameters(set, hash, 32, 64, 8, 14, 22, 16, 255);
370 case Sphincs_Parameter_Set::Sphincs256Fast:
371 case Sphincs_Parameter_Set::SLHDSA256Fast:
372 return Sphincs_Parameters(set, hash, 32, 68, 17, 9, 35, 16, 255);
373 }
375}
376
377Sphincs_Parameters Sphincs_Parameters::create(std::string_view name) {
378 auto [param_set, hash_type] = set_and_hash_from_name(name);
379 return Sphincs_Parameters::create(param_set, hash_type);
380}
381
382bool Sphincs_Parameters::is_slh_dsa() const {
383 return is_slh_dsa_set(m_set);
384}
385
386std::string Sphincs_Parameters::hash_name() const {
387 switch(m_hash_type) {
388 case Sphincs_Hash_Type::Sha256:
389 return "SHA-256";
390 case Sphincs_Hash_Type::Shake256:
391 return fmt("SHAKE-256({})", 8 * n());
392 case Sphincs_Hash_Type::Haraka:
393 return "Haraka";
394 }
396}
397
398std::string Sphincs_Parameters::to_string() const {
399 return name_from_set_and_hash(parameter_set(), hash_type());
400}
401
402Sphincs_Parameters Sphincs_Parameters::create(const OID& oid) {
403 return Sphincs_Parameters::create(oid.to_formatted_string());
404}
405
406OID Sphincs_Parameters::object_identifier() const {
407 return OID::from_string(to_string());
408}
409
410AlgorithmIdentifier Sphincs_Parameters::algorithm_identifier() const {
411 return AlgorithmIdentifier(object_identifier(), AlgorithmIdentifier::USE_EMPTY_PARAM);
412}
413
414} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
#define BOTAN_ASSERT_UNREACHABLE()
Definition assert.h:137
std::string to_formatted_string() const
Definition asn1_oid.cpp:139
std::string name
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 T ceil_tobytes(T bits)
Definition bit_ops.h:157
constexpr uint8_t ceil_log2(T x)
Definition bit_ops.h:122