Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PQC: SLH-DSA #4291

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
31 changes: 23 additions & 8 deletions doc/api_ref/pubkey.rst
Original file line number Diff line number Diff line change
Expand Up @@ -145,19 +145,34 @@ signatures, then the whole scheme becomes insecure, and signatures can be
forged.

HSS-LMS
-------
~~~~~~~

A post-quantum secure hash-based signature scheme similar to XMSS. Contains
support for multitrees. It is stateful, meaning the private key changes after
each signature.

SPHINCS+
~~~~~~~~~
SLH-DSA (FIPS 205)
~~~~~~~~~~~~~~~~~~

A post-quantum secure signature scheme whose security is based (only) on the
security of a hash function. Unlike XMSS, it is a stateless signature
scheme, meaning that the private key does not change with each signature. It
has high security but very long signatures and high runtime.
The Stateless Hash-Based Digital Signature Standard (SLH-DSA)
is the FIPS 205 post-quantum secure signature scheme whose security is solely
based on the security of a hash function. Unlike XMSS, it is a stateless
signature scheme, meaning that the private key does not change with each
signature. It has high security but very long signatures and high runtime.
FAlbertDev marked this conversation as resolved.
Show resolved Hide resolved

Support for SLH-DSA is implemented in the modules ``slh_dsa_sha2`` and ``slh_dsa_shake``.

Additionally, support for the pre-standardized version "SPHINCS+" is retained
for the time being. The implemented specification is commonly referred to as
version 3.1 of the SPHINCS+ submission to NIST's third round of the
PQC competition. This is not compatible with the "Initial Public Draft" version of
FIPS 205 for which Botan does not offer an implementation. Also, Botan does not
support the Haraka hash function.

Currently, two flavors of SPHINCS+ are implemented in separate Botan modules:

* ``sphincsplus_shake``, that uses Keccak (SHAKE) hash functions
* ``sphincsplus_sha2``, that uses SHA-256

FrodoKEM
~~~~~~~~
Expand Down Expand Up @@ -807,7 +822,7 @@ Botan implements the following signature algorithms:

#. Dilithium.
Takes the optional parameter ``Deterministic`` (default) or ``Randomized``.
#. SPHINCS+.
#. SLH-DSA.
Takes the optional parameter ``Deterministic`` (default) or ``Randomized``.
#. XMSS. Takes no parameter.
#. HSS-LMS. Takes no parameter.
Expand Down
4 changes: 2 additions & 2 deletions doc/credits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ snail-mail address (S), and Bitcoin address (B).
N: René Meusel
E: rene.meusel@rohde-schwarz.com
W: https://www.rohde-schwarz.com/cybersecurity
D: CI, TLS 1.3, Kyber, Dilithium, SPHINCS+, FrodoKEM
D: CI, TLS 1.3, Kyber, Dilithium, SLH-DSA, FrodoKEM
S: Berlin, Germany

N: Philippe Lieser
Expand All @@ -175,5 +175,5 @@ snail-mail address (S), and Bitcoin address (B).
N: Fabian Albert
E: fabian.albert@rohde-schwarz.com
W: https://www.rohde-schwarz.com/cybersecurity
D: SPHINCS+, HSS/LMS
D: SLH-DSA, HSS/LMS
S: Bochum, Germany
2 changes: 1 addition & 1 deletion readme.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ Public Key Cryptography
* RSA signatures and encryption
* DH and ECDH key agreement
* Signature schemes ECDSA, DSA, Ed25519, Ed448, ECGDSA, ECKCDSA, SM2, GOST 34.10
* Post-quantum signature schemes Dilithium, HSS/LMS, SPHINCS+, XMSS
* Post-quantum signature schemes Dilithium, HSS/LMS, SLH-DSA (SPHINCS+), XMSS
* Post-quantum key agreement schemes McEliece, Kyber, and FrodoKEM
* ElGamal encryption
* Padding schemes OAEP, PSS, PKCS #1 v1.5, X9.31
Expand Down
14 changes: 14 additions & 0 deletions src/build-data/oids.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@
1.3.6.1.4.1.25258.1.12.3.5 = SphincsPlus-haraka-256s-r3.1
1.3.6.1.4.1.25258.1.12.3.6 = SphincsPlus-haraka-256f-r3.1

# NIST: SLH-DSA
2.16.840.1.101.3.4.3.20 = SLH-DSA-SHA2-128s
2.16.840.1.101.3.4.3.21 = SLH-DSA-SHA2-128f
2.16.840.1.101.3.4.3.22 = SLH-DSA-SHA2-192s
2.16.840.1.101.3.4.3.23 = SLH-DSA-SHA2-192f
2.16.840.1.101.3.4.3.24 = SLH-DSA-SHA2-256s
2.16.840.1.101.3.4.3.25 = SLH-DSA-SHA2-256f
2.16.840.1.101.3.4.3.26 = SLH-DSA-SHAKE-128s
2.16.840.1.101.3.4.3.27 = SLH-DSA-SHAKE-128f
2.16.840.1.101.3.4.3.28 = SLH-DSA-SHAKE-192s
2.16.840.1.101.3.4.3.29 = SLH-DSA-SHAKE-192f
2.16.840.1.101.3.4.3.30 = SLH-DSA-SHAKE-256s
2.16.840.1.101.3.4.3.31 = SLH-DSA-SHAKE-256f

# XMSS
1.3.6.1.4.1.25258.1.5 = XMSS-draft6
1.3.6.1.4.1.25258.1.8 = XMSS-draft12
Expand Down
86 changes: 56 additions & 30 deletions src/cli/speed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@
#include <botan/hss_lms.h>
#endif

#if defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHA2) || defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHAKE)
#if defined(BOTAN_HAS_SPHINCS_PLUS_COMMON)
#include <botan/sphincsplus.h>
#endif

Expand Down Expand Up @@ -427,6 +427,7 @@ class Speed final : public Command {
"X448",
"McEliece",
"Kyber",
"SLH-DSA",
"SPHINCS+",
"FrodoKEM",
"HSS-LMS",
Expand Down Expand Up @@ -660,9 +661,11 @@ class Speed final : public Command {
bench_hss_lms(provider, msec);
}
#endif
#if defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHA2) || defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHAKE)
else if(algo == "SPHINCS+") {
bench_sphincs_plus(provider, msec);
#if defined(BOTAN_HAS_SPHINCS_PLUS_COMMON)
else if(algo == "SLH-DSA") {
bench_slh_dsa(provider, msec, true /* SLH-DSA */);
} else if(algo == "SPHINCS+") {
bench_slh_dsa(provider, msec, false /* SPHINCS+ */);
}
#endif
#if defined(BOTAN_HAS_FRODOKEM)
Expand Down Expand Up @@ -2263,35 +2266,58 @@ class Speed final : public Command {
}
#endif

#if defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHA2) || defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHAKE)
void bench_sphincs_plus(const std::string& provider, std::chrono::milliseconds msec) {
#if defined(BOTAN_HAS_SPHINCS_PLUS_COMMON)
void bench_slh_dsa(const std::string& provider, std::chrono::milliseconds msec, bool is_slh_dsa) {
// Sphincs_Parameter_Set set, Sphincs_Hash_Type hash
std::vector<std::string> sphincs_params{"SphincsPlus-sha2-128s-r3.1",
"SphincsPlus-sha2-128f-r3.1",
"SphincsPlus-sha2-192s-r3.1",
"SphincsPlus-sha2-192f-r3.1",
"SphincsPlus-sha2-256s-r3.1",
"SphincsPlus-sha2-256f-r3.1",
"SphincsPlus-shake-128s-r3.1",
"SphincsPlus-shake-128f-r3.1",
"SphincsPlus-shake-192s-r3.1",
"SphincsPlus-shake-192f-r3.1",
"SphincsPlus-shake-256s-r3.1",
"SphincsPlus-shake-256f-r3.1"};

for(auto params : sphincs_params) {
try {
auto keygen_timer = make_timer(params, provider, "keygen");
std::vector<std::string> instances_to_bench = [&]() -> std::vector<std::string> {
if(is_slh_dsa) {
// Bench the SLH-DSA instances
return {
"SLH-DSA-SHA2-128s",
"SLH-DSA-SHA2-128f",
"SLH-DSA-SHA2-192s",
"SLH-DSA-SHA2-192f",
"SLH-DSA-SHA2-256s",
"SLH-DSA-SHA2-256f",
"SLH-DSA-SHAKE-128s",
"SLH-DSA-SHAKE-128f",
"SLH-DSA-SHAKE-192s",
"SLH-DSA-SHAKE-192f",
"SLH-DSA-SHAKE-256s",
"SLH-DSA-SHAKE-256f",
};
} else {
// Bench the SPHINCS+ Round 3.1 instances
return {
"SphincsPlus-sha2-128s-r3.1",
"SphincsPlus-sha2-128f-r3.1",
"SphincsPlus-sha2-192s-r3.1",
"SphincsPlus-sha2-192f-r3.1",
"SphincsPlus-sha2-256s-r3.1",
"SphincsPlus-sha2-256f-r3.1",
"SphincsPlus-shake-128s-r3.1",
"SphincsPlus-shake-128f-r3.1",
"SphincsPlus-shake-192s-r3.1",
"SphincsPlus-shake-192f-r3.1",
"SphincsPlus-shake-256s-r3.1",
"SphincsPlus-shake-256f-r3.1",
};
}
}();

for(auto params_str : instances_to_bench) {
auto sp_params = Botan::Sphincs_Parameters::create(params_str);
if(!sp_params.is_available()) {
continue;
}
auto keygen_timer = make_timer(params_str, provider, "keygen");

std::unique_ptr<Botan::Private_Key> key(
keygen_timer->run([&] { return Botan::create_private_key("SPHINCS+", rng(), params); }));
std::unique_ptr<Botan::Private_Key> key(
keygen_timer->run([&] { return Botan::create_private_key("SLH-DSA", rng(), params_str); }));

record_result(keygen_timer);
if(bench_pk_sig(*key, params, provider, "", msec) == 1) {
break;
}
} catch(Botan::Not_Implemented&) {
continue;
record_result(keygen_timer);
if(bench_pk_sig(*key, params_str, provider, "", msec) == 1) {
break;
}
}
}
Expand Down
26 changes: 25 additions & 1 deletion src/lib/asn1/oid_maps.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* OID maps
*
* This file was automatically generated by ./src/scripts/dev_tools/gen_oids.py on 2024-07-23
* This file was automatically generated by ./src/scripts/dev_tools/gen_oids.py on 2024-09-20
*
* All manual edits to this file will be lost. Edit the script
* then regenerate this source file.
Expand Down Expand Up @@ -267,7 +267,19 @@ std::unordered_map<std::string, std::string> OID_Map::load_oid2str_map() {
{"2.16.840.1.101.3.4.3.15", "RSA/EMSA3(SHA-3(384))"},
{"2.16.840.1.101.3.4.3.16", "RSA/EMSA3(SHA-3(512))"},
{"2.16.840.1.101.3.4.3.2", "DSA/SHA-256"},
{"2.16.840.1.101.3.4.3.20", "SLH-DSA-SHA2-128s"},
{"2.16.840.1.101.3.4.3.21", "SLH-DSA-SHA2-128f"},
{"2.16.840.1.101.3.4.3.22", "SLH-DSA-SHA2-192s"},
{"2.16.840.1.101.3.4.3.23", "SLH-DSA-SHA2-192f"},
{"2.16.840.1.101.3.4.3.24", "SLH-DSA-SHA2-256s"},
{"2.16.840.1.101.3.4.3.25", "SLH-DSA-SHA2-256f"},
{"2.16.840.1.101.3.4.3.26", "SLH-DSA-SHAKE-128s"},
{"2.16.840.1.101.3.4.3.27", "SLH-DSA-SHAKE-128f"},
{"2.16.840.1.101.3.4.3.28", "SLH-DSA-SHAKE-192s"},
{"2.16.840.1.101.3.4.3.29", "SLH-DSA-SHAKE-192f"},
{"2.16.840.1.101.3.4.3.3", "DSA/SHA-384"},
{"2.16.840.1.101.3.4.3.30", "SLH-DSA-SHAKE-256s"},
{"2.16.840.1.101.3.4.3.31", "SLH-DSA-SHAKE-256f"},
{"2.16.840.1.101.3.4.3.4", "DSA/SHA-512"},
{"2.16.840.1.101.3.4.3.5", "DSA/SHA-3(224)"},
{"2.16.840.1.101.3.4.3.6", "DSA/SHA-3(256)"},
Expand Down Expand Up @@ -488,6 +500,18 @@ std::unordered_map<std::string, OID> OID_Map::load_str2oid_map() {
{"SHA-512-256", OID({2, 16, 840, 1, 101, 3, 4, 2, 6})},
{"SHAKE-128", OID({2, 16, 840, 1, 101, 3, 4, 2, 11})},
{"SHAKE-256", OID({2, 16, 840, 1, 101, 3, 4, 2, 12})},
{"SLH-DSA-SHA2-128f", OID({2, 16, 840, 1, 101, 3, 4, 3, 21})},
{"SLH-DSA-SHA2-128s", OID({2, 16, 840, 1, 101, 3, 4, 3, 20})},
{"SLH-DSA-SHA2-192f", OID({2, 16, 840, 1, 101, 3, 4, 3, 23})},
{"SLH-DSA-SHA2-192s", OID({2, 16, 840, 1, 101, 3, 4, 3, 22})},
{"SLH-DSA-SHA2-256f", OID({2, 16, 840, 1, 101, 3, 4, 3, 25})},
{"SLH-DSA-SHA2-256s", OID({2, 16, 840, 1, 101, 3, 4, 3, 24})},
{"SLH-DSA-SHAKE-128f", OID({2, 16, 840, 1, 101, 3, 4, 3, 27})},
{"SLH-DSA-SHAKE-128s", OID({2, 16, 840, 1, 101, 3, 4, 3, 26})},
{"SLH-DSA-SHAKE-192f", OID({2, 16, 840, 1, 101, 3, 4, 3, 29})},
{"SLH-DSA-SHAKE-192s", OID({2, 16, 840, 1, 101, 3, 4, 3, 28})},
{"SLH-DSA-SHAKE-256f", OID({2, 16, 840, 1, 101, 3, 4, 3, 31})},
{"SLH-DSA-SHAKE-256s", OID({2, 16, 840, 1, 101, 3, 4, 3, 30})},
{"SM2", OID({1, 2, 156, 10197, 1, 301, 1})},
{"SM2_Enc", OID({1, 2, 156, 10197, 1, 301, 3})},
{"SM2_Kex", OID({1, 2, 156, 10197, 1, 301, 2})},
Expand Down
16 changes: 9 additions & 7 deletions src/lib/pubkey/pk_algs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
#include <botan/dilithium.h>
#endif

#if defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHA2) || defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHAKE)
#if defined(BOTAN_HAS_SPHINCS_PLUS_COMMON)
#include <botan/sphincsplus.h>
#endif

Expand Down Expand Up @@ -230,8 +230,9 @@ std::unique_ptr<Public_Key> load_public_key(const AlgorithmIdentifier& alg_id,
}
#endif

#if defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHA2) || defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHAKE)
if(alg_name == "SPHINCS+" || alg_name.starts_with("SphincsPlus-")) {
#if defined(BOTAN_HAS_SPHINCS_PLUS_COMMON)
if(alg_name == "SPHINCS+" || alg_name.starts_with("SphincsPlus-") || alg_name.starts_with("SLH-DSA-") ||
alg_name.starts_with("Hash-SLH-DSA-")) {
return std::make_unique<SphincsPlus_PublicKey>(alg_id, key_bits);
}
#endif
Expand Down Expand Up @@ -365,8 +366,9 @@ std::unique_ptr<Private_Key> load_private_key(const AlgorithmIdentifier& alg_id,
}
#endif

#if defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHA2) || defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHAKE)
if(alg_name == "SPHINCS+" || alg_name.starts_with("SphincsPlus-")) {
#if defined(BOTAN_HAS_SPHINCS_PLUS_COMMON)
if(alg_name == "SPHINCS+" || alg_name.starts_with("SphincsPlus-") || alg_name.starts_with("SLH-DSA-") ||
alg_name.starts_with("Hash-SLH-DSA-")) {
return std::make_unique<SphincsPlus_PrivateKey>(alg_id, key_bits);
}
#endif
Expand Down Expand Up @@ -507,8 +509,8 @@ std::unique_ptr<Private_Key> create_private_key(std::string_view alg_name,
}
#endif

#if defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHA2) || defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHAKE)
if(alg_name == "SPHINCS+" || alg_name == "SphincsPlus-") {
#if defined(BOTAN_HAS_SPHINCS_PLUS_COMMON)
if(alg_name == "SPHINCS+" || alg_name == "SphincsPlus" || alg_name == "SLH-DSA") {
auto sphincs_params = Sphincs_Parameters::create(params);

return std::make_unique<SphincsPlus_PrivateKey>(rng, sphincs_params);
Expand Down
11 changes: 11 additions & 0 deletions src/lib/pubkey/sphincsplus/slh_dsa_sha2/info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<defines>
SLH_DSA_WITH_SHA2 -> 20240806
</defines>

<module_info>
name -> "SLH-DSA (SHA-256)"
</module_info>

<requires>
sphincsplus_sha2_base
</requires>
11 changes: 11 additions & 0 deletions src/lib/pubkey/sphincsplus/slh_dsa_shake/info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<defines>
SLH_DSA_WITH_SHAKE -> 20240808
</defines>

<module_info>
name -> "SLH-DSA (SHAKE)"
</module_info>

<requires>
sphincsplus_shake_base
</requires>
4 changes: 2 additions & 2 deletions src/lib/pubkey/sphincsplus/sphincsplus_common/info.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ SPHINCS_PLUS_COMMON -> 20230426
</defines>

<module_info>
name -> "SPHINCS+ (common)"
brief -> "Base implementation of SPHINCS+"
name -> "SLH-DSA (common)"
brief -> "Base implementation of Stateless Hash Function DSA"
type -> "Internal"
</module_info>

Expand Down
Loading
Loading