9#include <botan/internal/hss.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/fmt.h>
16#include <botan/internal/hss_lms_utils.h>
17#include <botan/internal/int_utils.h>
18#include <botan/internal/scan_name.h>
19#include <botan/internal/stateful_key_index_registry.h>
40constexpr uint16_t SEED_CHILD_SEED = 0xfffe;
47constexpr uint16_t SEED_CHILD_I = 0xffff;
52constexpr bool is_supported_hash_function(std::string_view hash_name) {
53 return hash_name ==
"SHA-256" || hash_name ==
"Truncated(SHA-256,192)" || hash_name ==
"SHAKE-256(256)" ||
54 hash_name ==
"SHAKE-256(192)";
61std::vector<LMS_Tree_Node_Idx> derive_lms_leaf_indices_from_hss_index(
HSS_Sig_Idx hss_idx,
63 std::vector<LMS_Tree_Node_Idx> q(hss_params.L().get());
64 for(int32_t layer_ctr = hss_params.L().get() - 1; layer_ctr >= 0; --layer_ctr) {
67 const size_t layer_h = layer_params.
lms_params().
h();
70 hss_idx = hss_idx >> layer_h;
81std::vector<uint8_t> hss_param_encoding(
const HSS_LMS_Params& params) {
82 std::vector<uint8_t> enc;
83 enc.reserve(
sizeof(uint32_t) * (1 + 2 * params.L().get()));
85 const auto append = [&](std::span<const uint8_t> bytes) { enc.insert(enc.end(), bytes.begin(), bytes.end()); };
88 for(
HSS_Level layer(0); layer < params.L(); ++layer) {
89 const auto& layer_params = params.params_at_level(layer);
90 append(
store_be(layer_params.lms_params().algorithm_type()));
91 append(
store_be(layer_params.lmots_params().algorithm_type()));
100 m_lms_lmots_params(std::move(lm_lmots_params)), m_max_sig_count(calc_max_sig_count()) {
101 BOTAN_ARG_CHECK(!m_lms_lmots_params.empty() && m_lms_lmots_params.size() <= HSS_MAX_LEVELS,
102 "Invalid number of levels");
106 const auto wrap_in_hss_lms = [&]() {
107 if(algo_params.starts_with(
"HSS-LMS(")) {
108 return std::string(algo_params);
110 return fmt(
"HSS-LMS({})", algo_params);
116 const std::string hash = scan.
arg(0);
117 BOTAN_ARG_CHECK(is_supported_hash_function(hash),
"Supported HSS-LMS hash function");
119 for(
size_t i = 1; i < scan.
arg_count(); ++i) {
126 "Invalid Winternitz parameter");
129 m_max_sig_count = calc_max_sig_count();
132HSS_Sig_Idx HSS_LMS_Params::calc_max_sig_count()
const {
133 uint32_t total_height_counter = 0;
134 for(
HSS_Level level(0); level <
L(); level++) {
137 if(total_height_counter >=
sizeof(
HSS_Sig_Idx) * 8) {
138 return HSS_Sig_Idx(std::numeric_limits<HSS_Sig_Idx::wrapped_type>::max());
145 m_hss_seed(rng.random_vec<
LMS_Seed>(m_hss_params.params_at_level(
HSS_Level(0)).lms_params().m())),
148 "HSS-LMS", hss_param_encoding(m_hss_params), m_hss_params.max_sig_count().get(), m_hss_seed, m_identifier),
154 m_hss_params(std::move(hss_params)),
155 m_hss_seed(std::move(hss_seed)),
156 m_identifier(std::move(identifier)),
158 "HSS-LMS", hss_param_encoding(m_hss_params), m_hss_params.max_sig_count().get(), m_hss_seed, m_identifier),
161 "Invalid HSS-LMS seed size");
166 std::span<const uint8_t> key_bytes) {
173 if(L == 0U || L > HSS_MAX_LEVELS) {
174 throw Decoding_Error(
"Invalid number of HSS layers in private HSS-LMS key.");
179 std::vector<HSS_LMS_Params::LMS_LMOTS_Params_Pair> params;
180 for(
size_t layer = 1; layer <= L; ++layer) {
182 throw Decoding_Error(
"Out of bytes while parsing private HSS-LMS key.");
188 const auto& hash_name = params.at(0).lms_params().hash_name();
190 for(
const auto& param : params) {
191 const bool invalid_lmots_hash = param.lmots_params().hash_name() != hash_name;
192 const bool invalid_lms_hash = param.lms_params().hash_name() != hash_name;
193 if(invalid_lmots_hash || invalid_lms_hash) {
194 throw Decoding_Error(
"Inconsistent hash functions are not allowed.");
199 throw Decoding_Error(
"Out of bytes while parsing private HSS-LMS key.");
201 auto hss_seed = slicer.
copy<
LMS_Seed>(params.at(0).lms_params().m());
204 if(!slicer.
empty()) {
205 throw Decoding_Error(
"Private HSS-LMS key contains more bytes than expected.");
207 auto sk = std::shared_ptr<HSS_LMS_PrivateKeyInternal>(
210 sk->set_idx(sig_idx);
228 stuffer.
append(m_hss_seed);
229 stuffer.
append(m_identifier);
241 if(idx > m_hss_params.max_sig_count()) {
247HSS_Sig_Idx HSS_LMS_PrivateKeyInternal::reserve_next_idx()
const {
249 if(!idx.has_value()) {
255size_t HSS_LMS_PrivateKeyInternal::size()
const {
259 sk_size += m_hss_seed.size() + m_identifier.size();
268 std::vector<LMS_Tree_Node_Idx> q = derive_lms_leaf_indices_from_hss_index(reserve_next_idx(),
hss_params());
271 std::vector<LMS_PrivateKey> lms_key_at_layer;
272 std::vector<StrongSpan<LMS_Signature_Bytes>> out_lms_sig_buffer_at_layer;
273 std::vector<std::span<uint8_t>> out_child_pk_buffer_at_layer;
280 lms_key_at_layer.push_back(
281 hss_derive_child_lms_private_key(layer_params, lms_key_at_layer.back(), q.at(layer.get() - 1)));
290 std::vector<uint8_t> current_pk;
291 for(int32_t layer_it =
hss_params().L().get() - 1; layer_it >= 0; --layer_it) {
295 lms_key_at_layer.at(layer.
get())
296 .sign_and_get_pk(out_lms_sig_buffer_at_layer.at(layer.
get()), q.at(layer.
get()),
LMS_Message(msg))
299 copy_mem(out_child_pk_buffer_at_layer.at(layer.
get()), current_pk);
301 lms_key_at_layer.at(layer.
get())
302 .sign_and_get_pk(out_lms_sig_buffer_at_layer.at(layer.
get()), q.at(layer.
get()),
LMS_Message(current_pk))
312 return LMS_PrivateKey(top_params.lms_params(), top_params.lmots_params(), m_identifier, m_hss_seed);
315LMS_PrivateKey HSS_LMS_PrivateKeyInternal::hss_derive_child_lms_private_key(
323 seed_generator.set_q(parent_q.
get());
324 seed_generator.set_i(SEED_CHILD_SEED);
325 seed_generator.set_j(0xff);
326 auto child_seed = seed_generator.gen<
LMS_Seed>(*hash, parent_sk.
seed());
329 seed_generator.set_i(SEED_CHILD_I);
336 std::move(child_identifier),
337 std::move(child_seed));
350 std::span<const uint8_t> key_bytes) {
351 if(key_bytes.size() <
sizeof(
HSS_Level)) {
357 if(L == 0U || L > HSS_MAX_LEVELS) {
358 throw Decoding_Error(
"Invalid number of HSS layers in public HSS-LMS key.");
363 if(!slicer.
empty()) {
364 throw Decoding_Error(
"Public HSS-LMS key contains more bytes than expected.");
366 return std::make_shared<HSS_LMS_PublicKeyInternal>(L, std::move(
lms_pub_key));
413 m_sig(std::move(sig)), m_pub(std::move(pub)) {}
416 if(sig_bytes.size() <
sizeof(uint32_t)) {
422 if(
Nspk >= HSS_MAX_LEVELS) {
423 throw Decoding_Error(
"Invalid number of HSS layers in signature.");
426 std::vector<Signed_Pub_Key> signed_pub_keys;
427 for(
size_t i = 0; i <
Nspk; ++i) {
430 signed_pub_keys.push_back(
Signed_Pub_Key(std::move(sig), std::move(pub_key)));
435 if(!slicer.
empty()) {
436 throw Decoding_Error(
"HSS-LMS signature contains more bytes than expected.");
438 return HSS_Signature(std::move(signed_pub_keys), std::move(sig));
442 size_t size =
sizeof(uint32_t);
445 for(
HSS_Level layer(1); layer < params.
L(); ++layer) {
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_ARG_CHECK(expr, msg)
auto copy(const size_t count)
std::span< const uint8_t > take(const size_t count)
Helper class to ease in-place marshalling of concatenated fixed-length values.
constexpr void append(std::span< const uint8_t > buffer)
constexpr std::span< uint8_t > next(size_t bytes)
constexpr bool full() const
Represents a pair of LMS and LMOTS parameters associated with one LMS tree layer.
const LMS_Params & lms_params() const
The LMS parameters.
const LMOTS_Params & lmots_params() const
The LMOTS parameters.
const LMS_LMOTS_Params_Pair & params_at_level(HSS_Level level) const
Returns the LMS an LM-OTS parameters at the specified level of the HSS tree.
HSS_Level L() const
Returns the number of layers the HSS tree has.
HSS_LMS_Params(std::vector< LMS_LMOTS_Params_Pair > lm_lmots_params)
Construct the HSS-LMS parameters from a vector LMS and LM-OTS parameters.
The internal HSS-LMS private key.
static std::shared_ptr< HSS_LMS_PrivateKeyInternal > from_bytes_or_throw(std::span< const uint8_t > key_bytes)
Parse a private HSS-LMS key.
const HSS_LMS_Params & hss_params() const
Returns the used HSS-LMS parameters.
LMS_PrivateKey hss_derive_root_lms_private_key() const
Create the HSS root LMS tree's LMS_PrivateKey using the HSS-LMS private key.
secure_vector< uint8_t > to_bytes() const
Returns the key in its encoded format.
void set_idx(HSS_Sig_Idx idx) const
Set the idx of the next signature to generate.
HSS_Sig_Idx remaining_operations() const
Get the number of remaining signatures for this key.
HSS_LMS_PrivateKeyInternal(const HSS_LMS_Params &hss_params, RandomNumberGenerator &rng)
Create an internal HSS-LMS private key.
std::vector< uint8_t > sign(std::span< const uint8_t > msg) const
Create a HSS-LMS signature.
static std::shared_ptr< HSS_LMS_PublicKeyInternal > from_bytes_or_throw(std::span< const uint8_t > key_bytes)
Parse a public HSS-LMS key.
bool verify_signature(std::span< const uint8_t > msg, const HSS_Signature &sig) const
Verify a HSS-LMS signature.
std::vector< uint8_t > to_bytes() const
Returns the key in its encoded format.
std::string algo_name() const
The algorithm name for HSS-LMS.
size_t size() const
Returns the size in bytes the key would have in its encoded format.
OID object_identifier() const
The object identifier for HSS-LMS.
static HSS_LMS_PublicKeyInternal create(const HSS_LMS_PrivateKeyInternal &hss_sk)
Create the public HSS-LMS key from its private key.
HSS_LMS_PublicKeyInternal(HSS_Level L, LMS_PublicKey top_lms_pub_key)
AlgorithmIdentifier algorithm_identifier() const
The algorithm identifier for HSS-LMS.
const LMS_PublicKey & lms_pub_key() const
Returns the public LMS key of the top LMS tree.
A LMS public key signed by the HSS layer above it.
Signed_Pub_Key(LMS_Signature sig, LMS_PublicKey pub)
Constructor for a new sig-pubkey-pair.
const LMS_Signature & signature() const
The signature of the public key.
const LMS_PublicKey & public_key() const
The signed public key.
static size_t size(const HSS_LMS_Params ¶ms)
Returns the size a signature would have in its encoded format.
const LMS_Signature & bottom_sig() const
Returns the LMS signature by the bottom layer of the signed message.
HSS_Level Nspk() const
Returns the number of signed public keys (Nspk = L-1).
const Signed_Pub_Key & signed_pub_key(HSS_Level layer) const
Returns the signed LMS key signed by a specific layer.
static HSS_Signature from_bytes_or_throw(std::span< const uint8_t > sig_bytes)
Parse a HSS-LMS signature.
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
static LMOTS_Params create_or_throw(LMOTS_Algorithm_Type type)
Create the LM-OTS parameters from a known algorithm type.
const std::string & hash_name() const
Name of the hash function to use.
const LMS_Params & lms_params() const
The LMS parameters for this LMS instance.
const LMOTS_Params & lmots_params() const
The LMOTS parameters used for OTS instances of this LMS instance.
const LMS_Identifier & identifier() const
The identifier of this LMS tree ('I' in RFC 8554).
const std::string & hash_name() const
Returns the name of the hash function to use.
uint8_t h() const
Returns the height of the LMS tree.
static LMS_Params create_or_throw(LMS_Algorithm_Type type)
Create the LMS parameters from a known algorithm type.
Representation of an LMS Private key.
const LMS_Seed & seed() const
The secret seed used for LMOTS' WOTS chain input creation (RFC 8554 Appendix A).
static size_t size(const LMS_Params &lms_params)
The expected size of an LMS public key for given lms_params.
std::vector< uint8_t > to_bytes() const
Bytes of the full lms public key according to 8554 5.3.
static LMS_PublicKey from_bytes_or_throw(BufferSlicer &slicer)
Parse a public LMS key.
bool verify_signature(const LMS_Message &msg, const LMS_Signature &sig) const
Verify a LMS signature.
Container for LMS Signature data.
static LMS_Signature from_bytes_or_throw(BufferSlicer &slicer)
Parse the bytes of a lms signature into a LMS Signature object.
static size_t size(const LMS_Params &lms_params, const LMOTS_Params &lmots_params)
static OID from_string(std::string_view str)
Helper class used to derive secret values based in the pseudorandom key generation described in RFC 8...
std::string arg(size_t i) const
const std::string & algo_name() const
size_t arg_as_integer(size_t i, size_t def_value) const
uint64_t current_index(const KeyId &key_id)
std::optional< uint64_t > reserve_next_index(const KeyId &key_id)
void set_index_lower_bound(const KeyId &key_id, uint64_t min)
static Stateful_Key_Index_Registry & global()
size_type size() const noexcept(noexcept(this->get().size()))
constexpr void unpoison(const T *p, size_t n)
LMS_Algorithm_Type
Enum of available LMS algorithm types.
std::string fmt(std::string_view format, const T &... args)
constexpr size_t LMS_IDENTIFIER_LEN
The length in bytes of the LMS identifier (I).
Strong< uint64_t, struct HSS_Sig_Idx_, EnableArithmeticWithPlainNumber > HSS_Sig_Idx
The index of a node within a specific LMS tree layer.
constexpr RT checked_cast_to(AT i)
Strong< std::vector< uint8_t >, struct LMS_Signature_Bytes_ > LMS_Signature_Bytes
Raw bytes of an LMS signature.
Strong< std::vector< uint8_t >, struct LMS_Identifier_ > LMS_Identifier
The identifier of an LMS tree (I in RFC 8554).
constexpr void copy_mem(T *out, const T *in, size_t n)
LMOTS_Algorithm_Type
Enum of available LM-OTS algorithm types.
Strong< secure_vector< uint8_t >, struct LMS_SEED_ > LMS_Seed
Seed of the LMS tree, used to generate the LM-OTS private keys.
constexpr RT checked_cast_to_or_throw(AT i, std::string_view error_msg_on_fail)
Strong< std::vector< uint8_t >, struct LMS_Message_ > LMS_Message
A message that is signed with an LMS tree.
constexpr auto concat(Rs &&... ranges)
Strong< uint32_t, struct HSS_Level_, EnableArithmeticWithPlainNumber > HSS_Level
The HSS layer in the HSS multi tree starting at 0 from the root.
Strong< uint32_t, struct LMS_Tree_Node_Idx_, EnableArithmeticWithPlainNumber > LMS_Tree_Node_Idx
The index of a node within a specific LMS tree layer.
std::vector< T, secure_allocator< T > > secure_vector
constexpr auto store_be(ParamTs &&... params)
constexpr auto load_be(ParamTs &&... params)