Skip to content

Commit

Permalink
Context support for ML-DSA and SLH-DSA
Browse files Browse the repository at this point in the history
  • Loading branch information
FAlbertDev committed Jan 17, 2025
1 parent de6d3aa commit 34786d9
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 32 deletions.
26 changes: 13 additions & 13 deletions src/lib/pubkey/dilithium/dilithium_common/dilithium.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ class Dilithium_Signature_Operation final : public PK_Ops::Signature {
m_s2(ntt(m_keypair.second->s2().clone())),
m_t0(ntt(m_keypair.second->t0().clone())),
m_A(Dilithium_Algos::expand_A(m_keypair.first->rho(), m_keypair.second->mode())) {
options.context().not_implemented("will come in Botan 3.7.0");
options.prehash().not_implemented("will come in Botan 3.7.0");
m_h->start(options.context().optional().value_or(std::vector<uint8_t>()));
options.prehash().not_implemented("HashML-DSA currently not supported");
}

void update(std::span<const uint8_t> input) override { m_h->update(input); }
Expand Down Expand Up @@ -259,11 +259,15 @@ class Dilithium_Signature_Operation final : public PK_Ops::Signature {

class Dilithium_Verification_Operation final : public PK_Ops::Verification {
public:
Dilithium_Verification_Operation(std::shared_ptr<Dilithium_PublicKeyInternal> pubkey) :
Dilithium_Verification_Operation(std::shared_ptr<Dilithium_PublicKeyInternal> pubkey,
PK_Signature_Options& options) :
m_pub_key(std::move(pubkey)),
m_A(Dilithium_Algos::expand_A(m_pub_key->rho(), m_pub_key->mode())),
m_t1_ntt_shifted(ntt(m_pub_key->t1() << DilithiumConstants::D)),
m_h(m_pub_key->mode().symmetric_primitives().get_message_hash(m_pub_key->tr())) {}
m_h(m_pub_key->mode().symmetric_primitives().get_message_hash(m_pub_key->tr())) {
m_h->start(options.context().optional().value_or(std::vector<uint8_t>()));
options.prehash().not_implemented("HashML-DSA currently not supported");
}

void update(std::span<const uint8_t> input) override { m_h->update(input); }

Expand Down Expand Up @@ -387,18 +391,16 @@ std::unique_ptr<Private_Key> Dilithium_PublicKey::generate_another(RandomNumberG
std::unique_ptr<PK_Ops::Verification> Dilithium_PublicKey::_create_verification_op(
PK_Signature_Options& options) const {
options.exclude_provider();
return std::make_unique<Dilithium_Verification_Operation>(m_public);
return std::make_unique<Dilithium_Verification_Operation>(m_public, options);
}

std::unique_ptr<PK_Ops::Verification> Dilithium_PublicKey::create_x509_verification_op(
const AlgorithmIdentifier& alg_id, std::string_view provider) const {
if(provider.empty() || provider == "base") {
if(alg_id != this->algorithm_identifier()) {
throw Decoding_Error("Unexpected AlgorithmIdentifier for Dilithium X.509 signature");
}
return std::make_unique<Dilithium_Verification_Operation>(m_public);
if(alg_id != this->algorithm_identifier()) {
throw Decoding_Error("Unexpected AlgorithmIdentifier for Dilithium X.509 signature");
}
throw Provider_Not_Found(algo_name(), provider);
auto options = PK_Verification_Options_Builder().with_provider(provider).commit();
return _create_verification_op(options);
}

/**
Expand Down Expand Up @@ -439,8 +441,6 @@ std::unique_ptr<PK_Ops::Signature> Dilithium_PrivateKey::_create_signature_op(Ra
PK_Signature_Options& options) const {
BOTAN_UNUSED(rng);
options.exclude_provider();
options.context().not_implemented("will come in Botan 3.7.0");
options.prehash().not_implemented("will come in Botan 3.7.0");
return std::make_unique<Dilithium_Signature_Operation>(DilithiumInternalKeypair{m_public, m_private}, options);
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib/pubkey/pk_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class BOTAN_UNSTABLE_API PK_Signature_Options final : public Options<detail::PK_

public:
/// It may be acceptable to provide a hash function, for hash-based
/// signatures (like SLH-DSA or LMS), but it is not required.
/// signatures (like LMS), but it is not required.
/// @throws Invalid_Argument if the provided hash is not acceptable
void validate_for_hash_based_signature(std::optional<std::string_view> acceptable_hash = std::nullopt);

Expand Down
32 changes: 14 additions & 18 deletions src/lib/pubkey/sphincsplus/sphincsplus_common/sphincsplus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,15 @@ std::unique_ptr<Private_Key> SphincsPlus_PublicKey::generate_another(RandomNumbe

class SphincsPlus_Verification_Operation final : public PK_Ops::Verification {
public:
SphincsPlus_Verification_Operation(std::shared_ptr<SphincsPlus_PublicKeyInternal> pub_key) :
SphincsPlus_Verification_Operation(std::shared_ptr<SphincsPlus_PublicKeyInternal> pub_key,
PK_Signature_Options& options) :
m_public(std::move(pub_key)),
m_hashes(Botan::Sphincs_Hash_Functions::create(m_public->parameters(), m_public->seed())),
m_context(/* TODO: Add API */ {}) {
m_context(options.context().optional().value_or(std::vector<uint8_t>())) {
BOTAN_ARG_CHECK(m_context.size() <= 255, "Context must not exceed 255 bytes");
BOTAN_ARG_CHECK(m_public->parameters().is_available(),
"The selected SLH-DSA (or SPHINCS+) instance is not available in this build.");
options.prehash().not_implemented("HashSLH-DSA currently not supported");
}

/**
Expand Down Expand Up @@ -241,19 +243,16 @@ class SphincsPlus_Verification_Operation final : public PK_Ops::Verification {
std::unique_ptr<PK_Ops::Verification> SphincsPlus_PublicKey::_create_verification_op(
PK_Signature_Options& options) const {
options.exclude_provider();
options.validate_for_hash_based_signature(m_public->parameters().hash_name());
return std::make_unique<SphincsPlus_Verification_Operation>(m_public);
return std::make_unique<SphincsPlus_Verification_Operation>(m_public, options);
}

std::unique_ptr<PK_Ops::Verification> SphincsPlus_PublicKey::create_x509_verification_op(
const AlgorithmIdentifier& signature_algorithm, std::string_view provider) const {
if(provider.empty() || provider == "base") {
if(signature_algorithm != this->algorithm_identifier()) {
throw Decoding_Error("Unexpected AlgorithmIdentifier for SLH-DSA (or SPHINCS+) signature");
}
return std::make_unique<SphincsPlus_Verification_Operation>(m_public);
if(signature_algorithm != this->algorithm_identifier()) {
throw Decoding_Error("Unexpected AlgorithmIdentifier for SLH-DSA (or SPHINCS+) signature");
}
throw Provider_Not_Found(algo_name(), provider);
auto options = PK_Verification_Options_Builder().with_provider(provider).commit();
return _create_verification_op(options);
}

bool SphincsPlus_PublicKey::supports_operation(PublicKeyOperation op) const {
Expand Down Expand Up @@ -335,15 +334,16 @@ class SphincsPlus_Signature_Operation final : public PK_Ops::Signature {
public:
SphincsPlus_Signature_Operation(std::shared_ptr<SphincsPlus_PrivateKeyInternal> private_key,
std::shared_ptr<SphincsPlus_PublicKeyInternal> public_key,
bool deterministic) :
PK_Signature_Options& options) :
m_private(std::move(private_key)),
m_public(std::move(public_key)),
m_hashes(Botan::Sphincs_Hash_Functions::create(m_public->parameters(), m_public->seed())),
m_deterministic(deterministic),
m_context(/* TODO: add API for context */ {}) {
m_deterministic(options.using_deterministic_signature()),
m_context(options.context().optional().value_or(std::vector<uint8_t>())) {
BOTAN_ARG_CHECK(m_context.size() <= 255, "Context must not exceed 255 bytes");
BOTAN_ARG_CHECK(m_public->parameters().is_available(),
"The selected SLH-DSA (or SPHINCS+) instance is not available in this build.");
options.prehash().not_implemented("HashSLH-DSA currently not supported");
}

void update(std::span<const uint8_t> msg) override {
Expand Down Expand Up @@ -424,15 +424,11 @@ std::unique_ptr<PK_Ops::Signature> SphincsPlus_PrivateKey::_create_signature_op(
PK_Signature_Options& options) const {
BOTAN_UNUSED(rng);
options.exclude_provider();
options.context().not_implemented("will come in Botan 3.7.0");
options.prehash().not_implemented("will come in Botan 3.7.0");
options.validate_for_hash_based_signature(m_public->parameters().hash_name());

// FIPS 205, Section 9.2
// The hedged variant is the default and should be used on platforms where
// side-channel attacks are a concern.
return std::make_unique<SphincsPlus_Signature_Operation>(
m_private, m_public, options.using_deterministic_signature());
return std::make_unique<SphincsPlus_Signature_Operation>(m_private, m_public, options);
}

} // namespace Botan

0 comments on commit 34786d9

Please sign in to comment.