Skip to content

Commit

Permalink
Apply review suggestions II
Browse files Browse the repository at this point in the history
  • Loading branch information
FAlbertDev committed Sep 20, 2024
1 parent fdc2290 commit 913c52a
Show file tree
Hide file tree
Showing 14 changed files with 84 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ SLH_DSA_WITH_SHA2 -> 20240806
<module_info>
name -> "SLH-DSA (SHA-256)"
</module_info>

<requires>
sphincsplus_sha2_base
</requires>
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ SLH_DSA_WITH_SHAKE -> 20240808
<module_info>
name -> "SLH-DSA (SHAKE)"
</module_info>

<requires>
sphincsplus_shake_base
</requires>
10 changes: 5 additions & 5 deletions src/lib/pubkey/sphincsplus/sphincsplus_common/sp_hash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
#include <botan/hash.h>
#include <botan/sp_parameters.h>

#if defined(BOTAN_HAS_SPHINCS_PLUS_SHAKE_BASED)
#if defined(BOTAN_HAS_SPHINCS_PLUS_SHAKE_BASE)
#include <botan/internal/sp_hash_shake.h>
#endif

#if defined(BOTAN_HAS_SPHINCS_PLUS_SHA2_BASED)
#if defined(BOTAN_HAS_SPHINCS_PLUS_SHA2_BASE)
#include <botan/internal/sp_hash_sha2.h>
#endif

Expand All @@ -35,14 +35,14 @@ std::unique_ptr<Sphincs_Hash_Functions> 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_Hash_Functions_Sha2>(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_Hash_Functions_Shake>(sphincs_params, pub_seed);
#else
throw Not_Implemented("SLH-DSA (or SPHINCS+) with SHAKE is not available in this build");
Expand Down Expand Up @@ -76,7 +76,7 @@ T from_first_n_bits(const uint32_t nbits, std::span<const uint8_t> bytes) {
} // namespace

std::tuple<SphincsHashedMessage, XmssTreeIndexInLayer, TreeNodeIndex> Sphincs_Hash_Functions::H_msg(
StrongSpan<const SphincsMessageRandomness> r, const SphincsTreeNode& root, std::span<const uint8_t> message) {
StrongSpan<const SphincsMessageRandomness> 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
Expand Down
8 changes: 5 additions & 3 deletions src/lib/pubkey/sphincsplus/sphincsplus_common/sp_hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ class BOTAN_TEST_API Sphincs_Hash_Functions {
const SphincsPublicSeed& pub_seed);

std::tuple<SphincsHashedMessage, XmssTreeIndexInLayer, TreeNodeIndex> H_msg(
StrongSpan<const SphincsMessageRandomness> r, const SphincsTreeNode& root, std::span<const uint8_t> message);
StrongSpan<const SphincsMessageRandomness> r,
const SphincsTreeNode& root,
const SphincsMessageInternal& message);

/**
* Using SK.PRF, the optional randomness, and a message, computes the message random R,
Expand All @@ -49,7 +51,7 @@ class BOTAN_TEST_API Sphincs_Hash_Functions {
virtual void PRF_msg(StrongSpan<SphincsMessageRandomness> out,
StrongSpan<const SphincsSecretPRF> sk_prf,
StrongSpan<const SphincsOptionalRandomness> opt_rand,
std::span<const uint8_t> msg) = 0;
const SphincsMessageInternal& msg) = 0;

template <typename... BufferTs>
void T(std::span<uint8_t> out, const Sphincs_Address& address, BufferTs&&... in) {
Expand Down Expand Up @@ -95,7 +97,7 @@ class BOTAN_TEST_API Sphincs_Hash_Functions {

virtual std::vector<uint8_t> H_msg_digest(StrongSpan<const SphincsMessageRandomness> r,
const SphincsTreeNode& root,
std::span<const uint8_t> message) = 0;
const SphincsMessageInternal& message) = 0;

const Sphincs_Parameters& m_sphincs_params;
const SphincsPublicSeed& m_pub_seed;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
14 changes: 14 additions & 0 deletions src/lib/pubkey/sphincsplus/sphincsplus_common/sp_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::vector<uint8_t>, struct SphincsMessagePrefix_>;
// The input to [hash_]slh_sign and [hash_]slh_verify
using SphincsInputMessage = Strong<std::vector<uint8_t>, 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<std::vector<uint8_t>, struct SphincsContext_>;

using SphincsHashedMessage = Strong<std::vector<uint8_t>, struct SphincsHashedMessage_>;
using SphincsPublicSeed = Strong<std::vector<uint8_t>, struct SphincsPublicSeed_>;
using SphincsSecretSeed = Strong<secure_vector<uint8_t>, struct SphincsSecretSeed_>;
Expand Down
41 changes: 20 additions & 21 deletions src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,24 @@ namespace Botan {

namespace {
// FIPS 205, Algorithm 22, line 8
std::vector<uint8_t> prepare_message(std::vector<uint8_t> msg,
const Sphincs_Parameters& params,
std::span<const uint8_t> context) {
SphincsMessageInternal prepare_message(SphincsInputMessage&& msg,
const Sphincs_Parameters& params,
StrongSpan<const SphincsContext> 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<uint8_t> 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<uint8_t>(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

Expand Down Expand Up @@ -184,22 +183,22 @@ class SphincsPlus_Verification_Operation final : public PK_Ops::Verification {
*/
void update(std::span<const uint8_t> 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<const uint8_t> 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<const uint8_t> msg, std::span<const uint8_t> sig) {
bool slh_verify_internal(const SphincsMessageInternal& msg, std::span<const uint8_t> sig) {
const auto& p = m_public->parameters();
if(sig.size() != p.sphincs_signature_bytes()) {
return false;
Expand All @@ -224,8 +223,8 @@ class SphincsPlus_Verification_Operation final : public PK_Ops::Verification {

std::shared_ptr<SphincsPlus_PublicKeyInternal> m_public;
std::unique_ptr<Sphincs_Hash_Functions> m_hashes;
std::vector<uint8_t> m_msg_buffer;
std::vector<uint8_t> m_context;
SphincsInputMessage m_msg_buffer;
SphincsContext m_context;
};

std::unique_ptr<PK_Ops::Verification> SphincsPlus_PublicKey::create_verification_op(std::string_view /*params*/,
Expand Down Expand Up @@ -337,17 +336,17 @@ class SphincsPlus_Signature_Operation final : public PK_Ops::Signature {

void update(std::span<const uint8_t> 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<uint8_t> sign(RandomNumberGenerator& rng) override {
std::optional<SphincsOptionalRandomness> addrnd = std::nullopt;
if(m_randomized) {
addrnd = rng.random_vec<SphincsOptionalRandomness>(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(); }
Expand All @@ -360,7 +359,7 @@ class SphincsPlus_Signature_Operation final : public PK_Ops::Signature {

private:
// FIPS 205, Algorithm 19
std::vector<uint8_t> slh_sign_internal(std::span<const uint8_t> message,
std::vector<uint8_t> slh_sign_internal(const SphincsMessageInternal& message,
std::optional<StrongSpan<const SphincsOptionalRandomness>> addrnd) {
const auto& p = m_public->parameters();

Expand Down Expand Up @@ -404,9 +403,9 @@ class SphincsPlus_Signature_Operation final : public PK_Ops::Signature {
std::shared_ptr<SphincsPlus_PrivateKeyInternal> m_private;
std::shared_ptr<SphincsPlus_PublicKeyInternal> m_public;
std::unique_ptr<Sphincs_Hash_Functions> m_hashes;
std::vector<uint8_t> m_msg_buffer;
SphincsInputMessage m_msg_buffer;
bool m_randomized;
std::vector<uint8_t> m_context;
SphincsContext m_context;
};

std::unique_ptr<PK_Ops::Signature> SphincsPlus_PrivateKey::create_signature_op(RandomNumberGenerator& rng,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<defines>
SPHINCS_PLUS_SHA2_BASED -> 20240807
SPHINCS_PLUS_SHA2_BASE -> 20240807
</defines>

<module_info>
Expand All @@ -9,7 +9,6 @@ type -> "Internal"
</module_info>

<requires>
sphincsplus_common
sha2_32
sha2_64
mgf1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@ class Sphincs_Hash_Functions_Sha2 : public Sphincs_Hash_Functions {

std::vector<uint8_t> H_msg_digest(StrongSpan<const SphincsMessageRandomness> r,
const SphincsTreeNode& root,
std::span<const uint8_t> 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<uint8_t> mgf1_input = concat<std::vector<uint8_t>>(r, m_pub_seed, r_pk_buffer);
Expand Down Expand Up @@ -90,11 +91,12 @@ class Sphincs_Hash_Functions_Sha2 : public Sphincs_Hash_Functions {
void PRF_msg(StrongSpan<SphincsMessageRandomness> out,
StrongSpan<const SphincsSecretPRF> sk_prf,
StrongSpan<const SphincsOptionalRandomness> opt_rand,
std::span<const uint8_t> 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());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<defines>
SPHINCS_PLUS_SHAKE_BASED -> 20240809
SPHINCS_PLUS_SHAKE_BASE -> 20240809
</defines>

<module_info>
Expand All @@ -9,7 +9,6 @@ type -> "Internal"
</module_info>

<requires>
sphincsplus_common
shake
</requires>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ class Sphincs_Hash_Functions_Shake : public Sphincs_Hash_Functions {

std::vector<uint8_t> H_msg_digest(StrongSpan<const SphincsMessageRandomness> r,
const SphincsTreeNode& root,
std::span<const uint8_t> 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();
}
Expand All @@ -50,10 +51,11 @@ class Sphincs_Hash_Functions_Shake : public Sphincs_Hash_Functions {
void PRF_msg(StrongSpan<SphincsMessageRandomness> out,
StrongSpan<const SphincsSecretPRF> sk_prf,
StrongSpan<const SphincsOptionalRandomness> opt_rand,
std::span<const uint8_t> 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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ SPHINCS_PLUS_WITH_SHA2 -> 20230531
<module_info>
name -> "SPHINCS+ (SHA-256)"
</module_info>

<requires>
sphincsplus_sha2_base
</requires>
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ SPHINCS_PLUS_WITH_SHAKE -> 20230531
<module_info>
name -> "SPHINCS+ (SHAKE-256)"
</module_info>

<requires>
sphincsplus_shake_base
</requires>
11 changes: 9 additions & 2 deletions src/tests/test_sphincsplus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t> seed_ref = vars.get_req_bin("seed");
const std::vector<uint8_t> msg_ref = vars.get_req_bin("msg");
Expand Down Expand Up @@ -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 {
Expand All @@ -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);
Expand Down

0 comments on commit 913c52a

Please sign in to comment.