9#include <botan/sphincsplus.h>
12#include <botan/internal/buffer_slicer.h>
13#include <botan/internal/buffer_stuffer.h>
14#include <botan/internal/concat_util.h>
15#include <botan/internal/int_utils.h>
16#include <botan/internal/pk_ops_impl.h>
17#include <botan/internal/sp_fors.h>
18#include <botan/internal/sp_hash.h>
19#include <botan/internal/sp_hypertree.h>
20#include <botan/internal/sp_treehash.h>
21#include <botan/internal/sp_types.h>
22#include <botan/internal/sp_wots.h>
23#include <botan/internal/sp_xmss.h>
27#if !defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHA2) and !defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHAKE) and \
28 !defined(BOTAN_HAS_SLH_DSA_WITH_SHA2) and !defined(BOTAN_HAS_SLH_DSA_WITH_SHAKE)
31 "botan module 'sphincsplus_common' is useful only when enabling at least 'sphincsplus_sha2', 'sphincsplus_shake', 'slh_dsa_sha2', or 'slh_dsa_shake'");
41 BOTAN_ARG_CHECK(params.is_slh_dsa() || context.empty(),
"Context is not supported for SPHINCS+");
42#if defined(BOTAN_HAS_SLH_DSA_WITH_SHA2) || defined(BOTAN_HAS_SLH_DSA_WITH_SHAKE)
43 if(params.is_slh_dsa()) {
45 const uint8_t input_mode_byte = 0x00;
49 .message = std::move(msg),
53#if defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHA2) || defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHAKE)
54 if(!params.is_slh_dsa()) {
58 .message = std::move(msg),
62 throw Internal_Error(
"Missing message preparation logic for SLH-DSA or SPHINCS+");
66class SphincsPlus_PublicKeyInternal final {
68 SphincsPlus_PublicKeyInternal(Sphincs_Parameters params,
71 m_params(params), m_public_seed(std::move(public_seed)), m_sphincs_root(std::move(sphincs_root)) {}
73 SphincsPlus_PublicKeyInternal(Sphincs_Parameters params, std::span<const uint8_t> key_bits) : m_params(params) {
74 if(key_bits.size() != m_params.public_key_bytes()) {
75 throw Decoding_Error(
"SLH-DSA (or SPHINCS+) Public Key doesn't have the expected length");
78 BufferSlicer s(key_bits);
91 const Sphincs_Parameters& parameters()
const {
return m_params; }
94 Sphincs_Parameters m_params;
99class SphincsPlus_PrivateKeyInternal final {
102 m_secret_seed(std::move(secret_seed)), m_prf(std::move(prf)) {}
104 SphincsPlus_PrivateKeyInternal(
const Sphincs_Parameters& params, std::span<const uint8_t> key_bits) {
105 if(key_bits.size() != params.private_key_bytes() - params.public_key_bytes()) {
106 throw Decoding_Error(
"SLH-DSA (or SPHINCS+) Private Key doesn't have the expected length");
109 BufferSlicer s(key_bits);
133 m_public(std::make_shared<SphincsPlus_PublicKeyInternal>(params, pub_key)) {
135 throw Not_Implemented(
"This SPHINCS+ parameter set is not available in this configuration");
145 return m_public->parameters().n() * 8;
149 return m_public->parameters().is_slh_dsa() ?
"SLH-DSA" :
"SPHINCS+";
153 return m_public->parameters().bitsec();
157 return m_public->parameters().algorithm_identifier();
161 return m_public->parameters().object_identifier();
180 return std::make_unique<SphincsPlus_PrivateKey>(rng,
m_public->parameters());
187 explicit SphincsPlus_Verification_Operation(std::shared_ptr<SphincsPlus_PublicKeyInternal> pub_key) :
188 m_public(std::move(pub_key)),
191 BOTAN_ARG_CHECK(m_context.size() <= 255,
"Context must not exceed 255 bytes");
193 if(!m_public->parameters().is_available()) {
194 throw Not_Implemented(
"This SPHINCS+ parameter set is not available in this configuration");
202 void update(std::span<const uint8_t> msg)
override {
204 m_msg_buffer.get().insert(m_msg_buffer.end(), msg.begin(), msg.end());
210 bool is_valid_signature(std::span<const uint8_t> sig)
override {
211 const auto internal_msg = prepare_message(std::exchange(m_msg_buffer, {}), m_public->parameters(), m_context);
212 return slh_verify_internal(internal_msg, sig);
215 std::string hash_function()
const override {
return m_hashes->msg_hash_function_name(); }
219 bool slh_verify_internal(
const SphincsMessageInternal& msg, std::span<const uint8_t> sig) {
220 const auto& p = m_public->parameters();
221 if(sig.size() != p.sphincs_signature_bytes()) {
228 auto [mhash, tree_idx, leaf_idx] = m_hashes->H_msg(msg_random_s, m_public->root(), msg);
232 fors_addr.set_tree_address(tree_idx).set_keypair_address(leaf_idx);
233 const auto fors_sig_s = s.take<
ForsSignature>(p.fors_signature_bytes());
239 return ht_verify(fors_root, ht_sig_s, m_public->root(), tree_idx, leaf_idx, p, *m_hashes);
242 std::shared_ptr<SphincsPlus_PublicKeyInternal> m_public;
243 std::unique_ptr<Sphincs_Hash_Functions> m_hashes;
251 std::string_view provider)
const {
252 if(provider.empty() || provider ==
"base") {
253 return std::make_unique<SphincsPlus_Verification_Operation>(
m_public);
260 if(provider.empty() || provider ==
"base") {
262 throw Decoding_Error(
"Unexpected AlgorithmIdentifier for SLH-DSA (or SPHINCS+) signature");
264 return std::make_unique<SphincsPlus_Verification_Operation>(
m_public);
275std::span<const uint8_t> slice_off_public_key(
const OID& oid, std::span<const uint8_t> key_bits) {
282 if(key_bits.size() != params.private_key_bytes()) {
283 throw Decoding_Error(
"Sphincs Private Key doesn't have the expected length");
286 return key_bits.subspan(params.private_key_bytes() - params.public_key_bytes());
302 throw Not_Implemented(
"This SPHINCS+ parameter set is not available in this configuration");
308 m_private = std::make_shared<SphincsPlus_PrivateKeyInternal>(params, private_key.first(private_portion_bytes));
319 throw Not_Implemented(
"This SPHINCS+ parameter set is not available in this configuration");
324 m_private = std::make_shared<SphincsPlus_PrivateKeyInternal>(std::move(sk_seed), std::move(sk_prf));
330 m_public = std::make_shared<SphincsPlus_PublicKeyInternal>(params, std::move(pub_seed), std::move(
root));
344 return std::make_unique<SphincsPlus_PublicKey>(*
this);
351 SphincsPlus_Signature_Operation(std::shared_ptr<SphincsPlus_PrivateKeyInternal> private_key,
352 std::shared_ptr<SphincsPlus_PublicKeyInternal> public_key,
354 m_private(std::move(private_key)),
355 m_public(std::move(public_key)),
357 m_randomized(randomized),
359 BOTAN_ARG_CHECK(m_context.size() <= 255,
"Context must not exceed 255 bytes");
361 "The selected SLH-DSA (or SPHINCS+) instance is not available in this build.");
364 void update(std::span<const uint8_t> msg)
override {
366 m_msg_buffer.get().insert(m_msg_buffer.end(), msg.begin(), msg.end());
369 std::vector<uint8_t> sign(RandomNumberGenerator& rng)
override {
370 std::optional<SphincsOptionalRandomness> addrnd = std::nullopt;
374 auto internal_msg = prepare_message(std::exchange(m_msg_buffer, {}), m_public->parameters(), m_context);
376 return slh_sign_internal(internal_msg, addrnd);
379 size_t signature_length()
const override {
return m_public->parameters().sphincs_signature_bytes(); }
381 AlgorithmIdentifier algorithm_identifier()
const override {
382 return m_public->parameters().algorithm_identifier();
385 std::string hash_function()
const override {
return m_hashes->msg_hash_function_name(); }
389 std::vector<uint8_t> slh_sign_internal(
const SphincsMessageInternal& message,
390 std::optional<StrongSpan<const SphincsOptionalRandomness>> addrnd) {
391 const auto& p = m_public->parameters();
393 std::vector<uint8_t> sphincs_sig_buffer(p.sphincs_signature_bytes());
394 BufferStuffer sphincs_sig(sphincs_sig_buffer);
398 const auto opt_rand =
399 (addrnd.has_value()) ? addrnd.value() : StrongSpan<const SphincsOptionalRandomness>(m_public->seed());
402 m_hashes->PRF_msg(msg_random_s, m_private->prf(), opt_rand, message);
405 auto [mhash, tree_idx, leaf_idx] = m_hashes->H_msg(msg_random_s, m_public->root(), message);
409 fors_addr.set_tree_address(tree_idx).set_keypair_address(leaf_idx);
427 return sphincs_sig_buffer;
430 std::shared_ptr<SphincsPlus_PrivateKeyInternal> m_private;
431 std::shared_ptr<SphincsPlus_PublicKeyInternal> m_public;
432 std::unique_ptr<Sphincs_Hash_Functions> m_hashes;
441 std::string_view params,
442 std::string_view provider)
const {
444 BOTAN_ARG_CHECK(params.empty() || params ==
"Deterministic" || params ==
"Randomized",
445 "Unexpected parameters for signing with SLH-DSA (or SPHINCS+)");
450 const bool randomized = (params.empty() || params ==
"Randomized");
451 if(provider.empty() || provider ==
"base") {
452 return std::make_unique<SphincsPlus_Signature_Operation>(m_private,
m_public, randomized);
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_ARG_CHECK(expr, msg)
void random_vec(std::span< uint8_t > v)
secure_vector< uint8_t > raw_private_key_bits() const override
std::unique_ptr< PK_Ops::Signature > create_signature_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
~SphincsPlus_PrivateKey() override
SphincsPlus_PrivateKey(std::span< const uint8_t > private_key, Sphincs_Parameter_Set type, Sphincs_Hash_Type hash)
secure_vector< uint8_t > private_key_bits() const override
std::unique_ptr< Public_Key > public_key() const override
std::vector< uint8_t > public_key_bits() const override
std::vector< uint8_t > raw_public_key_bits() const override
std::unique_ptr< PK_Ops::Verification > create_x509_verification_op(const AlgorithmIdentifier &signature_algorithm, std::string_view provider) const override
std::unique_ptr< PK_Ops::Verification > create_verification_op(std::string_view params, std::string_view provider) const override
bool supports_operation(PublicKeyOperation op) const override
~SphincsPlus_PublicKey() override
std::string algo_name() const override
size_t key_length() const override
std::unique_ptr< Private_Key > generate_another(RandomNumberGenerator &rng) const final
bool check_key(RandomNumberGenerator &rng, bool strong) const override
AlgorithmIdentifier algorithm_identifier() const override
SphincsPlus_PublicKey()=default
std::shared_ptr< SphincsPlus_PublicKeyInternal > m_public
size_t estimated_strength() const override
SphincsPlus_PublicKey(std::span< const uint8_t > pub_key, Sphincs_Parameter_Set type, Sphincs_Hash_Type hash)
OID object_identifier() const override
static std::unique_ptr< Sphincs_Hash_Functions > create(const Sphincs_Parameters &sphincs_params, const SphincsPublicSeed &pub_seed)
uint32_t private_key_bytes() const
uint32_t public_key_bytes() const
bool is_available() const
static Sphincs_Parameters create(Sphincs_Parameter_Set set, Sphincs_Hash_Type hash)
Gf448Elem root(const Gf448Elem &elem)
Compute the root of elem in the field.
Strong< std::vector< uint8_t >, struct SphincsTreeNode_ > SphincsTreeNode
Either an XMSS or FORS tree node or leaf.
SphincsTreeNode xmss_gen_root(const Sphincs_Parameters ¶ms, const SphincsSecretSeed &secret_seed, Sphincs_Hash_Functions &hashes)
Strong< secure_vector< uint8_t >, struct SphincsMessageRandomness_ > SphincsMessageRandomness
constexpr RT checked_cast_to(AT i)
SphincsTreeNode fors_sign_and_pkgen(StrongSpan< ForsSignature > sig_out, const SphincsHashedMessage &hashed_message, const SphincsSecretSeed &secret_seed, const Sphincs_Address &address, const Sphincs_Parameters ¶ms, Sphincs_Hash_Functions &hashes)
FIPS 205, Algorithm 16: fors_sign (with simultaneous FORS pk generation).
Strong< std::vector< uint8_t >, struct ForsSignature_ > ForsSignature
void ht_sign(StrongSpan< SphincsHypertreeSignature > out_sig, const SphincsTreeNode &message_to_sign, const SphincsSecretSeed &secret_seed, XmssTreeIndexInLayer tree_index_in_layer, TreeNodeIndex idx_leaf, const Sphincs_Parameters ¶ms, Sphincs_Hash_Functions &hashes)
FIPS 205, Algorithm 12: ht_sign.
bool ht_verify(const SphincsTreeNode &signed_msg, StrongSpan< const SphincsHypertreeSignature > ht_sig, const SphincsTreeNode &pk_root, XmssTreeIndexInLayer tree_index_in_layer, TreeNodeIndex idx_leaf, const Sphincs_Parameters ¶ms, Sphincs_Hash_Functions &hashes)
FIPS 205, Algorithm 13: ht_verify.
Strong< std::vector< uint8_t >, struct SphincsXmssSignature_ > SphincsHypertreeSignature
Strong< std::vector< uint8_t >, struct SphincsInputMessage_ > SphincsInputMessage
Strong< std::vector< uint8_t >, struct SphincsPublicSeed_ > SphincsPublicSeed
Strong< secure_vector< uint8_t >, struct SphincsSecretSeed_ > SphincsSecretSeed
Strong< secure_vector< uint8_t >, struct SphincsSecretPRF_ > SphincsSecretPRF
constexpr auto concat(Rs &&... ranges)
SphincsTreeNode fors_public_key_from_signature(const SphincsHashedMessage &hashed_message, StrongSpan< const ForsSignature > signature, const Sphincs_Address &address, const Sphincs_Parameters ¶ms, Sphincs_Hash_Functions &hashes)
FIPS 205, Algorithm 17: fors_pkFromSig.
std::vector< T, secure_allocator< T > > secure_vector
Strong< secure_vector< uint8_t >, struct SphincsOptionalRandomness_ > SphincsOptionalRandomness
constexpr auto store_be(ParamTs &&... params)
Strong< std::vector< uint8_t >, struct SphincsContext_ > SphincsContext
M' representation of FIPS 205 (the input to slh_sign_internal and slh_verify_internal).