9#include <botan/sphincsplus.h>
12#include <botan/internal/int_utils.h>
13#include <botan/internal/pk_ops_impl.h>
14#include <botan/internal/sp_fors.h>
15#include <botan/internal/sp_hash.h>
16#include <botan/internal/sp_hypertree.h>
17#include <botan/internal/sp_treehash.h>
18#include <botan/internal/sp_types.h>
19#include <botan/internal/sp_wots.h>
20#include <botan/internal/sp_xmss.h>
21#include <botan/internal/stl_util.h>
25#if !defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHA2) and !defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHAKE) and \
26 !defined(BOTAN_HAS_SLH_DSA_WITH_SHA2) and !defined(BOTAN_HAS_SLH_DSA_WITH_SHAKE)
29 "botan module 'sphincsplus_common' is useful only when enabling at least 'sphincsplus_sha2', 'sphincsplus_shake', 'slh_dsa_sha2', or 'slh_dsa_shake'");
37 const Sphincs_Parameters& params,
38 StrongSpan<const SphincsContext> context) {
39 BOTAN_ARG_CHECK(params.is_slh_dsa() || context.empty(),
"Context is not supported for SPHINCS+");
40#if defined(BOTAN_HAS_SLH_DSA_WITH_SHA2) || defined(BOTAN_HAS_SLH_DSA_WITH_SHAKE)
41 if(params.is_slh_dsa()) {
43 const uint8_t input_mode_byte = 0x00;
47 .message = std::move(msg),
51#if defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHA2) || defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHAKE)
52 if(!params.is_slh_dsa()) {
56 .message = std::move(msg),
60 throw Internal_Error(
"Missing message preparation logic for SLH-DSA or SPHINCS+");
64class SphincsPlus_PublicKeyInternal
final {
66 SphincsPlus_PublicKeyInternal(Sphincs_Parameters params,
69 m_params(params), m_public_seed(std::move(public_seed)), m_sphincs_root(std::move(sphincs_root)) {}
71 SphincsPlus_PublicKeyInternal(Sphincs_Parameters params, std::span<const uint8_t> key_bits) : m_params(params) {
73 throw Decoding_Error(
"SLH-DSA (or SPHINCS+) Public Key doesn't have the expected length");
76 BufferSlicer s(key_bits);
89 const Sphincs_Parameters& parameters()
const {
return m_params; }
92 Sphincs_Parameters m_params;
97class SphincsPlus_PrivateKeyInternal
final {
100 m_secret_seed(std::move(secret_seed)), m_prf(std::move(prf)) {}
102 SphincsPlus_PrivateKeyInternal(
const Sphincs_Parameters& params, std::span<const uint8_t> key_bits) {
103 if(key_bits.size() != params.private_key_bytes() - params.public_key_bytes()) {
104 throw Decoding_Error(
"SLH-DSA (or SPHINCS+) Private Key doesn't have the expected length");
107 BufferSlicer s(key_bits);
131 m_public(std::make_shared<SphincsPlus_PublicKeyInternal>(params, pub_key)) {
133 "The selected parameter-set-hash combination is not activated in this build.");
142 return m_public->parameters().n() * 8;
146 return m_public->parameters().is_slh_dsa() ?
"SLH-DSA" :
"SPHINCS+";
150 return m_public->parameters().bitsec();
158 return m_public->parameters().object_identifier();
177 return std::make_unique<SphincsPlus_PrivateKey>(rng,
m_public->parameters());
182 SphincsPlus_Verification_Operation(std::shared_ptr<SphincsPlus_PublicKeyInternal> pub_key) :
183 m_public(std::move(pub_key)),
186 BOTAN_ARG_CHECK(m_context.size() <= 255,
"Context must not exceed 255 bytes");
188 "The selected SLH-DSA (or SPHINCS+) instance is not available in this build.");
195 void update(std::span<const uint8_t> msg)
override {
197 m_msg_buffer.
get().insert(m_msg_buffer.end(), msg.begin(), msg.end());
203 bool is_valid_signature(std::span<const uint8_t> sig)
override {
204 const auto internal_msg = prepare_message(std::exchange(m_msg_buffer, {}), m_public->parameters(), m_context);
205 return slh_verify_internal(internal_msg, sig);
208 std::string hash_function()
const override {
return m_hashes->msg_hash_function_name(); }
212 bool slh_verify_internal(
const SphincsMessageInternal& msg, std::span<const uint8_t> sig) {
213 const auto& p = m_public->parameters();
214 if(sig.size() != p.sphincs_signature_bytes()) {
221 auto [mhash, tree_idx, leaf_idx] = m_hashes->H_msg(msg_random_s, m_public->root(), msg);
225 fors_addr.set_tree_address(tree_idx).set_keypair_address(leaf_idx);
226 const auto fors_sig_s = s.take<
ForsSignature>(p.fors_signature_bytes());
232 return ht_verify(fors_root, ht_sig_s, m_public->root(), tree_idx, leaf_idx, p, *m_hashes);
235 std::shared_ptr<SphincsPlus_PublicKeyInternal> m_public;
236 std::unique_ptr<Sphincs_Hash_Functions> m_hashes;
242 std::string_view provider)
const {
243 if(provider.empty() || provider ==
"base") {
244 return std::make_unique<SphincsPlus_Verification_Operation>(
m_public);
251 if(provider.empty() || provider ==
"base") {
253 throw Decoding_Error(
"Unexpected AlgorithmIdentifier for SLH-DSA (or SPHINCS+) signature");
255 return std::make_unique<SphincsPlus_Verification_Operation>(
m_public);
266std::span<const uint8_t> slice_off_public_key(
const OID& oid, std::span<const uint8_t> key_bits) {
273 if(key_bits.size() != params.private_key_bytes()) {
274 throw Decoding_Error(
"Sphincs Private Key doesn't have the expected length");
277 return key_bits.subspan(params.private_key_bytes() - params.public_key_bytes());
293 "The selected parameter-set-hash combination is not activated in this build.");
297 m_private = std::make_shared<SphincsPlus_PrivateKeyInternal>(params, private_key.first(private_portion_bytes));
308 "The selected parameter-set-hash combination is not activated in this build.");
312 m_private = std::make_shared<SphincsPlus_PrivateKeyInternal>(std::move(sk_seed), std::move(sk_prf));
318 m_public = std::make_shared<SphincsPlus_PublicKeyInternal>(params, std::move(pub_seed), std::move(
root));
332 return std::make_unique<SphincsPlus_PublicKey>(*
this);
337 SphincsPlus_Signature_Operation(std::shared_ptr<SphincsPlus_PrivateKeyInternal> private_key,
338 std::shared_ptr<SphincsPlus_PublicKeyInternal> public_key,
340 m_private(std::move(private_key)),
341 m_public(std::move(public_key)),
343 m_randomized(randomized),
345 BOTAN_ARG_CHECK(m_context.size() <= 255,
"Context must not exceed 255 bytes");
347 "The selected SLH-DSA (or SPHINCS+) instance is not available in this build.");
350 void update(std::span<const uint8_t> msg)
override {
352 m_msg_buffer.
get().insert(m_msg_buffer.end(), msg.begin(), msg.end());
355 std::vector<uint8_t> sign(RandomNumberGenerator& rng)
override {
356 std::optional<SphincsOptionalRandomness> addrnd = std::nullopt;
360 auto internal_msg = prepare_message(std::exchange(m_msg_buffer, {}), m_public->parameters(), m_context);
362 return slh_sign_internal(internal_msg, addrnd);
365 size_t signature_length()
const override {
return m_public->parameters().sphincs_signature_bytes(); }
367 AlgorithmIdentifier algorithm_identifier()
const override {
368 return m_public->parameters().algorithm_identifier();
371 std::string hash_function()
const override {
return m_hashes->msg_hash_function_name(); }
375 std::vector<uint8_t> slh_sign_internal(
const SphincsMessageInternal& message,
376 std::optional<StrongSpan<const SphincsOptionalRandomness>> addrnd) {
377 const auto& p = m_public->parameters();
379 std::vector<uint8_t> sphincs_sig_buffer(p.sphincs_signature_bytes());
380 BufferStuffer sphincs_sig(sphincs_sig_buffer);
384 const auto opt_rand =
385 (addrnd.has_value()) ? addrnd.value() : StrongSpan<const SphincsOptionalRandomness>(m_public->seed());
388 m_hashes->PRF_msg(msg_random_s, m_private->prf(), opt_rand, message);
391 auto [mhash, tree_idx, leaf_idx] = m_hashes->H_msg(msg_random_s, m_public->root(), message);
395 fors_addr.set_tree_address(tree_idx).set_keypair_address(leaf_idx);
413 return sphincs_sig_buffer;
416 std::shared_ptr<SphincsPlus_PrivateKeyInternal> m_private;
417 std::shared_ptr<SphincsPlus_PublicKeyInternal> m_public;
418 std::unique_ptr<Sphincs_Hash_Functions> m_hashes;
425 std::string_view params,
426 std::string_view provider)
const {
428 BOTAN_ARG_CHECK(params.empty() || params ==
"Deterministic" || params ==
"Randomized",
429 "Unexpected parameters for signing with SLH-DSA (or SPHINCS+)");
434 const bool randomized = (params.empty() || params ==
"Randomized");
435 if(provider.empty() || provider ==
"base") {
436 return std::make_unique<SphincsPlus_Signature_Operation>(m_private,
m_public, randomized);
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_ARG_CHECK(expr, msg)
const std::vector< uint8_t > & parameters() const
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
An SLH-DSA (or SPHINCS+ Round 3.1) public key.
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
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)
int(* update)(CTX *, const void *, CC_LONG len)
int(* final)(unsigned char *, CTX *)
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