From 913c52a238afa56b49c4d4d382dae7e4ece7f7e2 Mon Sep 17 00:00:00 2001 From: Fabian Albert Date: Fri, 20 Sep 2024 14:13:10 +0200 Subject: [PATCH] Apply review suggestions II --- .../slh_dsa_sha2/info.txt | 4 ++ .../slh_dsa_shake/info.txt | 4 ++ .../sphincsplus_common/sp_hash.cpp | 10 ++--- .../sphincsplus/sphincsplus_common/sp_hash.h | 8 ++-- .../sphincsplus_common/sp_parameters.cpp | 2 +- .../sphincsplus/sphincsplus_common/sp_types.h | 14 +++++++ .../sphincsplus_common/sphincsplus.cpp | 41 +++++++++---------- .../sphincsplus_sha2_base}/info.txt | 3 +- .../sphincsplus_sha2_base}/sp_hash_sha2.h | 10 +++-- .../sphincsplus_shake_base}/info.txt | 3 +- .../sphincsplus_shake_base}/sp_hash_shake.h | 10 +++-- .../sphincsplus_sha2/info.txt | 4 ++ .../sphincsplus_shake/info.txt | 4 ++ src/tests/test_sphincsplus.cpp | 11 ++++- 14 files changed, 84 insertions(+), 44 deletions(-) rename src/lib/pubkey/sphincsplus/{sphincsplus_sha2_based => }/slh_dsa_sha2/info.txt (70%) rename src/lib/pubkey/sphincsplus/{sphincsplus_shake_based => }/slh_dsa_shake/info.txt (69%) rename src/lib/pubkey/sphincsplus/{sphincsplus_sha2_based => sphincsplus_common/sphincsplus_sha2_base}/info.txt (83%) rename src/lib/pubkey/sphincsplus/{sphincsplus_sha2_based => sphincsplus_common/sphincsplus_sha2_base}/sp_hash_sha2.h (93%) rename src/lib/pubkey/sphincsplus/{sphincsplus_shake_based => sphincsplus_common/sphincsplus_shake_base}/info.txt (81%) rename src/lib/pubkey/sphincsplus/{sphincsplus_shake_based => sphincsplus_common/sphincsplus_shake_base}/sp_hash_shake.h (86%) rename src/lib/pubkey/sphincsplus/{sphincsplus_sha2_based => }/sphincsplus_sha2/info.txt (71%) rename src/lib/pubkey/sphincsplus/{sphincsplus_shake_based => }/sphincsplus_shake/info.txt (71%) diff --git a/src/lib/pubkey/sphincsplus/sphincsplus_sha2_based/slh_dsa_sha2/info.txt b/src/lib/pubkey/sphincsplus/slh_dsa_sha2/info.txt similarity index 70% rename from src/lib/pubkey/sphincsplus/sphincsplus_sha2_based/slh_dsa_sha2/info.txt rename to src/lib/pubkey/sphincsplus/slh_dsa_sha2/info.txt index 3e6def1c6e5..4f5d1b9e4ea 100644 --- a/src/lib/pubkey/sphincsplus/sphincsplus_sha2_based/slh_dsa_sha2/info.txt +++ b/src/lib/pubkey/sphincsplus/slh_dsa_sha2/info.txt @@ -5,3 +5,7 @@ SLH_DSA_WITH_SHA2 -> 20240806 name -> "SLH-DSA (SHA-256)" + + +sphincsplus_sha2_base + diff --git a/src/lib/pubkey/sphincsplus/sphincsplus_shake_based/slh_dsa_shake/info.txt b/src/lib/pubkey/sphincsplus/slh_dsa_shake/info.txt similarity index 69% rename from src/lib/pubkey/sphincsplus/sphincsplus_shake_based/slh_dsa_shake/info.txt rename to src/lib/pubkey/sphincsplus/slh_dsa_shake/info.txt index 764228cc356..d775089b0bd 100644 --- a/src/lib/pubkey/sphincsplus/sphincsplus_shake_based/slh_dsa_shake/info.txt +++ b/src/lib/pubkey/sphincsplus/slh_dsa_shake/info.txt @@ -5,3 +5,7 @@ SLH_DSA_WITH_SHAKE -> 20240808 name -> "SLH-DSA (SHAKE)" + + +sphincsplus_shake_base + diff --git a/src/lib/pubkey/sphincsplus/sphincsplus_common/sp_hash.cpp b/src/lib/pubkey/sphincsplus/sphincsplus_common/sp_hash.cpp index 31add7b1d07..c9fee7e387c 100644 --- a/src/lib/pubkey/sphincsplus/sphincsplus_common/sp_hash.cpp +++ b/src/lib/pubkey/sphincsplus/sphincsplus_common/sp_hash.cpp @@ -15,11 +15,11 @@ #include #include -#if defined(BOTAN_HAS_SPHINCS_PLUS_SHAKE_BASED) +#if defined(BOTAN_HAS_SPHINCS_PLUS_SHAKE_BASE) #include #endif -#if defined(BOTAN_HAS_SPHINCS_PLUS_SHA2_BASED) +#if defined(BOTAN_HAS_SPHINCS_PLUS_SHA2_BASE) #include #endif @@ -35,14 +35,14 @@ std::unique_ptr Sphincs_Hash_Functions::create(const Sph const SphincsPublicSeed& pub_seed) { switch(sphincs_params.hash_type()) { case Sphincs_Hash_Type::Sha256: -#if defined(BOTAN_HAS_SPHINCS_PLUS_SHA2_BASED) +#if defined(BOTAN_HAS_SPHINCS_PLUS_SHA2_BASE) return std::make_unique(sphincs_params, pub_seed); #else throw Not_Implemented("SLH-DSA (or SPHINCS+) with SHA-256 is not available in this build"); #endif case Sphincs_Hash_Type::Shake256: -#if defined(BOTAN_HAS_SPHINCS_PLUS_SHAKE_BASED) +#if defined(BOTAN_HAS_SPHINCS_PLUS_SHAKE_BASE) return std::make_unique(sphincs_params, pub_seed); #else throw Not_Implemented("SLH-DSA (or SPHINCS+) with SHAKE is not available in this build"); @@ -76,7 +76,7 @@ T from_first_n_bits(const uint32_t nbits, std::span bytes) { } // namespace std::tuple Sphincs_Hash_Functions::H_msg( - StrongSpan r, const SphincsTreeNode& root, std::span message) { + StrongSpan r, const SphincsTreeNode& root, const SphincsMessageInternal& message) { const auto digest = H_msg_digest(r, root, message); // The following calculates the message digest and indices from the diff --git a/src/lib/pubkey/sphincsplus/sphincsplus_common/sp_hash.h b/src/lib/pubkey/sphincsplus/sphincsplus_common/sp_hash.h index f546bbd6796..f80998075f9 100644 --- a/src/lib/pubkey/sphincsplus/sphincsplus_common/sp_hash.h +++ b/src/lib/pubkey/sphincsplus/sphincsplus_common/sp_hash.h @@ -35,7 +35,9 @@ class BOTAN_TEST_API Sphincs_Hash_Functions { const SphincsPublicSeed& pub_seed); std::tuple H_msg( - StrongSpan r, const SphincsTreeNode& root, std::span message); + StrongSpan r, + const SphincsTreeNode& root, + const SphincsMessageInternal& message); /** * Using SK.PRF, the optional randomness, and a message, computes the message random R, @@ -49,7 +51,7 @@ class BOTAN_TEST_API Sphincs_Hash_Functions { virtual void PRF_msg(StrongSpan out, StrongSpan sk_prf, StrongSpan opt_rand, - std::span msg) = 0; + const SphincsMessageInternal& msg) = 0; template void T(std::span out, const Sphincs_Address& address, BufferTs&&... in) { @@ -95,7 +97,7 @@ class BOTAN_TEST_API Sphincs_Hash_Functions { virtual std::vector H_msg_digest(StrongSpan r, const SphincsTreeNode& root, - std::span message) = 0; + const SphincsMessageInternal& message) = 0; const Sphincs_Parameters& m_sphincs_params; const SphincsPublicSeed& m_pub_seed; diff --git a/src/lib/pubkey/sphincsplus/sphincsplus_common/sp_parameters.cpp b/src/lib/pubkey/sphincsplus/sphincsplus_common/sp_parameters.cpp index d5ccfbb0c90..2aa26899eb6 100644 --- a/src/lib/pubkey/sphincsplus/sphincsplus_common/sp_parameters.cpp +++ b/src/lib/pubkey/sphincsplus/sphincsplus_common/sp_parameters.cpp @@ -338,7 +338,7 @@ bool Sphincs_Parameters::is_available() const { return true; } #endif -#ifdef BOTAN_HAS_SPHINCS_PLUS_SHAKE_BASED +#ifdef BOTAN_HAS_SPHINCS_PLUS_WITH_SHAKE if(!is_slh_dsa && m_hash_type == Sphincs_Hash_Type::Shake256) { return true; } diff --git a/src/lib/pubkey/sphincsplus/sphincsplus_common/sp_types.h b/src/lib/pubkey/sphincsplus/sphincsplus_common/sp_types.h index 6d73dd503d5..37abf89f01b 100644 --- a/src/lib/pubkey/sphincsplus/sphincsplus_common/sp_types.h +++ b/src/lib/pubkey/sphincsplus/sphincsplus_common/sp_types.h @@ -42,6 +42,20 @@ namespace Botan { * [WotsNode || ... || WotsNode] contains len WotsNodes, each of length n bytes. */ +/// The prefix appended to the message in [hash_]slh_sign and slh_verify. +/// E.g. for SLH-DSA (pure): 0x00 || |ctx| || ctx. Empty for SPHINCS+. +using SphincsMessagePrefix = Strong, struct SphincsMessagePrefix_>; +// The input to [hash_]slh_sign and [hash_]slh_verify +using SphincsInputMessage = Strong, struct SphincsInputMessage_>; + +/// M' representation of FIPS 205 (the input to slh_sign_internal and slh_verify_internal) +struct SphincsMessageInternal { + SphincsMessagePrefix prefix; + SphincsInputMessage message; +}; + +using SphincsContext = Strong, struct SphincsContext_>; + using SphincsHashedMessage = Strong, struct SphincsHashedMessage_>; using SphincsPublicSeed = Strong, struct SphincsPublicSeed_>; using SphincsSecretSeed = Strong, struct SphincsSecretSeed_>; diff --git a/src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus.cpp b/src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus.cpp index 19ceb41c4df..bb793254fa4 100644 --- a/src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus.cpp +++ b/src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus.cpp @@ -33,25 +33,24 @@ namespace Botan { namespace { // FIPS 205, Algorithm 22, line 8 -std::vector prepare_message(std::vector msg, - const Sphincs_Parameters& params, - std::span context) { +SphincsMessageInternal prepare_message(SphincsInputMessage&& msg, + const Sphincs_Parameters& params, + StrongSpan context) { + BOTAN_ARG_CHECK(params.is_slh_dsa() || context.empty(), "Context is not supported for SPHINCS+"); + SphincsMessageInternal msg_internal{.prefix = SphincsMessagePrefix(), .message = std::move(msg)}; if(params.is_slh_dsa()) { // prefix (no pre-hash mode): input mode byte + |ctx| + ctx - std::vector prefix(1 + 1 + context.size()); - BufferStuffer prefix_stuffer(prefix); + msg_internal.prefix = SphincsMessagePrefix(1 + 1 + context.size()); + BufferStuffer prefix_stuffer(msg_internal.prefix); const uint8_t input_mode_byte = 0x00; // Pure (TODO: pre-hash mode: 0x01) prefix_stuffer.append(input_mode_byte); prefix_stuffer.append(checked_cast_to(context.size())); prefix_stuffer.append(context); BOTAN_ASSERT_NOMSG(prefix_stuffer.full()); - - msg.insert(msg.begin(), prefix.begin(), prefix.end()); } // else: SPHINCS+ Round 3.1 uses the message without any prefix - - return msg; + return msg_internal; } } // namespace @@ -184,22 +183,22 @@ class SphincsPlus_Verification_Operation final : public PK_Ops::Verification { */ void update(std::span msg) override { // TODO(For Pre-Hash Mode): We need to stream the message into a hash function. - m_msg_buffer.insert(m_msg_buffer.end(), msg.begin(), msg.end()); + m_msg_buffer.get().insert(m_msg_buffer.end(), msg.begin(), msg.end()); } /** * Perform a verification operation */ bool is_valid_signature(std::span sig) override { - const auto msg = prepare_message(std::exchange(m_msg_buffer, {}), m_public->parameters(), m_context); - return slh_verify_internal(msg, sig); + const auto internal_msg = prepare_message(std::exchange(m_msg_buffer, {}), m_public->parameters(), m_context); + return slh_verify_internal(internal_msg, sig); } std::string hash_function() const override { return m_hashes->msg_hash_function_name(); } private: /// FIPS 205, Algorithm 20 - bool slh_verify_internal(std::span msg, std::span sig) { + bool slh_verify_internal(const SphincsMessageInternal& msg, std::span sig) { const auto& p = m_public->parameters(); if(sig.size() != p.sphincs_signature_bytes()) { return false; @@ -224,8 +223,8 @@ class SphincsPlus_Verification_Operation final : public PK_Ops::Verification { std::shared_ptr m_public; std::unique_ptr m_hashes; - std::vector m_msg_buffer; - std::vector m_context; + SphincsInputMessage m_msg_buffer; + SphincsContext m_context; }; std::unique_ptr SphincsPlus_PublicKey::create_verification_op(std::string_view /*params*/, @@ -337,7 +336,7 @@ class SphincsPlus_Signature_Operation final : public PK_Ops::Signature { void update(std::span msg) override { // TODO(For Pre-Hash Mode): We need to stream the message into a hash function. - m_msg_buffer.insert(m_msg_buffer.end(), msg.begin(), msg.end()); + m_msg_buffer.get().insert(m_msg_buffer.end(), msg.begin(), msg.end()); } std::vector sign(RandomNumberGenerator& rng) override { @@ -345,9 +344,9 @@ class SphincsPlus_Signature_Operation final : public PK_Ops::Signature { if(m_randomized) { addrnd = rng.random_vec(m_public->parameters().n()); } - auto msg = prepare_message(std::exchange(m_msg_buffer, {}), m_public->parameters(), m_context); + auto internal_msg = prepare_message(std::exchange(m_msg_buffer, {}), m_public->parameters(), m_context); - return slh_sign_internal(msg, addrnd); + return slh_sign_internal(internal_msg, addrnd); } size_t signature_length() const override { return m_public->parameters().sphincs_signature_bytes(); } @@ -360,7 +359,7 @@ class SphincsPlus_Signature_Operation final : public PK_Ops::Signature { private: // FIPS 205, Algorithm 19 - std::vector slh_sign_internal(std::span message, + std::vector slh_sign_internal(const SphincsMessageInternal& message, std::optional> addrnd) { const auto& p = m_public->parameters(); @@ -404,9 +403,9 @@ class SphincsPlus_Signature_Operation final : public PK_Ops::Signature { std::shared_ptr m_private; std::shared_ptr m_public; std::unique_ptr m_hashes; - std::vector m_msg_buffer; + SphincsInputMessage m_msg_buffer; bool m_randomized; - std::vector m_context; + SphincsContext m_context; }; std::unique_ptr SphincsPlus_PrivateKey::create_signature_op(RandomNumberGenerator& rng, diff --git a/src/lib/pubkey/sphincsplus/sphincsplus_sha2_based/info.txt b/src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus_sha2_base/info.txt similarity index 83% rename from src/lib/pubkey/sphincsplus/sphincsplus_sha2_based/info.txt rename to src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus_sha2_base/info.txt index 212bc14bcc7..78b9864c19b 100644 --- a/src/lib/pubkey/sphincsplus/sphincsplus_sha2_based/info.txt +++ b/src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus_sha2_base/info.txt @@ -1,5 +1,5 @@ -SPHINCS_PLUS_SHA2_BASED -> 20240807 +SPHINCS_PLUS_SHA2_BASE -> 20240807 @@ -9,7 +9,6 @@ type -> "Internal" -sphincsplus_common sha2_32 sha2_64 mgf1 diff --git a/src/lib/pubkey/sphincsplus/sphincsplus_sha2_based/sp_hash_sha2.h b/src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus_sha2_base/sp_hash_sha2.h similarity index 93% rename from src/lib/pubkey/sphincsplus/sphincsplus_sha2_based/sp_hash_sha2.h rename to src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus_sha2_base/sp_hash_sha2.h index 4fa49403afd..b8f2bcd8e47 100644 --- a/src/lib/pubkey/sphincsplus/sphincsplus_sha2_based/sp_hash_sha2.h +++ b/src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus_sha2_base/sp_hash_sha2.h @@ -44,11 +44,12 @@ class Sphincs_Hash_Functions_Sha2 : public Sphincs_Hash_Functions { std::vector H_msg_digest(StrongSpan r, const SphincsTreeNode& root, - std::span message) override { + const SphincsMessageInternal& message) override { m_sha_x_full->update(r); m_sha_x_full->update(m_pub_seed); m_sha_x_full->update(root); - m_sha_x_full->update(message); + m_sha_x_full->update(message.prefix); + m_sha_x_full->update(message.message); auto r_pk_buffer = m_sha_x_full->final(); std::vector mgf1_input = concat>(r, m_pub_seed, r_pk_buffer); @@ -90,11 +91,12 @@ class Sphincs_Hash_Functions_Sha2 : public Sphincs_Hash_Functions { void PRF_msg(StrongSpan out, StrongSpan sk_prf, StrongSpan opt_rand, - std::span msg) override { + const SphincsMessageInternal& msg) override { HMAC hmac_sha_x(m_sha_x_full->new_object()); hmac_sha_x.set_key(sk_prf); hmac_sha_x.update(opt_rand); - hmac_sha_x.update(msg); + hmac_sha_x.update(msg.prefix); + hmac_sha_x.update(msg.message); const auto prf = hmac_sha_x.final(); std::copy(prf.begin(), prf.begin() + out.size(), out.begin()); diff --git a/src/lib/pubkey/sphincsplus/sphincsplus_shake_based/info.txt b/src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus_shake_base/info.txt similarity index 81% rename from src/lib/pubkey/sphincsplus/sphincsplus_shake_based/info.txt rename to src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus_shake_base/info.txt index 66272357ee3..6552c588bfa 100644 --- a/src/lib/pubkey/sphincsplus/sphincsplus_shake_based/info.txt +++ b/src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus_shake_base/info.txt @@ -1,5 +1,5 @@ -SPHINCS_PLUS_SHAKE_BASED -> 20240809 +SPHINCS_PLUS_SHAKE_BASE -> 20240809 @@ -9,7 +9,6 @@ type -> "Internal" -sphincsplus_common shake diff --git a/src/lib/pubkey/sphincsplus/sphincsplus_shake_based/sp_hash_shake.h b/src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus_shake_base/sp_hash_shake.h similarity index 86% rename from src/lib/pubkey/sphincsplus/sphincsplus_shake_based/sp_hash_shake.h rename to src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus_shake_base/sp_hash_shake.h index 0bc3ab9dba9..2d74f0685b4 100644 --- a/src/lib/pubkey/sphincsplus/sphincsplus_shake_based/sp_hash_shake.h +++ b/src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus_shake_base/sp_hash_shake.h @@ -29,11 +29,12 @@ class Sphincs_Hash_Functions_Shake : public Sphincs_Hash_Functions { std::vector H_msg_digest(StrongSpan r, const SphincsTreeNode& root, - std::span message) override { + const SphincsMessageInternal& message) override { m_h_msg_hash.update(r); m_h_msg_hash.update(m_pub_seed); m_h_msg_hash.update(root); - m_h_msg_hash.update(message); + m_h_msg_hash.update(message.prefix); + m_h_msg_hash.update(message.message); return m_h_msg_hash.final_stdvec(); } @@ -50,10 +51,11 @@ class Sphincs_Hash_Functions_Shake : public Sphincs_Hash_Functions { void PRF_msg(StrongSpan out, StrongSpan sk_prf, StrongSpan opt_rand, - std::span msg) override { + const SphincsMessageInternal& msg) override { m_hash.update(sk_prf); m_hash.update(opt_rand); - m_hash.update(msg); + m_hash.update(msg.prefix); + m_hash.update(msg.message); m_hash.final(out); } diff --git a/src/lib/pubkey/sphincsplus/sphincsplus_sha2_based/sphincsplus_sha2/info.txt b/src/lib/pubkey/sphincsplus/sphincsplus_sha2/info.txt similarity index 71% rename from src/lib/pubkey/sphincsplus/sphincsplus_sha2_based/sphincsplus_sha2/info.txt rename to src/lib/pubkey/sphincsplus/sphincsplus_sha2/info.txt index aa59dd99970..a0b66de0cf5 100644 --- a/src/lib/pubkey/sphincsplus/sphincsplus_sha2_based/sphincsplus_sha2/info.txt +++ b/src/lib/pubkey/sphincsplus/sphincsplus_sha2/info.txt @@ -5,3 +5,7 @@ SPHINCS_PLUS_WITH_SHA2 -> 20230531 name -> "SPHINCS+ (SHA-256)" + + +sphincsplus_sha2_base + diff --git a/src/lib/pubkey/sphincsplus/sphincsplus_shake_based/sphincsplus_shake/info.txt b/src/lib/pubkey/sphincsplus/sphincsplus_shake/info.txt similarity index 71% rename from src/lib/pubkey/sphincsplus/sphincsplus_shake_based/sphincsplus_shake/info.txt rename to src/lib/pubkey/sphincsplus/sphincsplus_shake/info.txt index a07157c43d8..f315ac8a25a 100644 --- a/src/lib/pubkey/sphincsplus/sphincsplus_shake_based/sphincsplus_shake/info.txt +++ b/src/lib/pubkey/sphincsplus/sphincsplus_shake/info.txt @@ -5,3 +5,7 @@ SPHINCS_PLUS_WITH_SHAKE -> 20230531 name -> "SPHINCS+ (SHAKE-256)" + + +sphincsplus_shake_base + diff --git a/src/tests/test_sphincsplus.cpp b/src/tests/test_sphincsplus.cpp index 858a84e7a13..bf64b43cae5 100644 --- a/src/tests/test_sphincsplus.cpp +++ b/src/tests/test_sphincsplus.cpp @@ -67,9 +67,8 @@ class SPHINCS_Plus_Test_Base : public Text_Based_Test { } Test::Result run_one_test(const std::string&, const VarMap& vars) final { - Test::Result result("SLH-DSA"); - auto params = Botan::Sphincs_Parameters::create(vars.get_req_str("SphincsParameterSet")); + Test::Result result(params.is_slh_dsa() ? "SLH-DSA" : "SPHINCS+"); const std::vector seed_ref = vars.get_req_bin("seed"); const std::vector msg_ref = vars.get_req_bin("msg"); @@ -260,6 +259,10 @@ class Generic_SlhDsa_Signature_Tests final : public PK_Signature_Generation_Test } std::string default_padding(const VarMap&) const override { return ""; } + + bool skip_this_test(const std::string&, const VarMap& vars) override { + return !Botan::Sphincs_Parameters::create(vars.get_req_str("Instance")).is_available(); + } }; class Generic_SlhDsa_Verification_Tests final : public PK_Signature_Verification_Test { @@ -278,6 +281,10 @@ class Generic_SlhDsa_Verification_Tests final : public PK_Signature_Verification } std::string default_padding(const VarMap&) const override { return ""; } + + bool skip_this_test(const std::string&, const VarMap& vars) override { + return !Botan::Sphincs_Parameters::create(vars.get_req_str("Instance")).is_available(); + } }; BOTAN_REGISTER_TEST("pubkey", "sphincsplus", SPHINCS_Plus_Test);