9#include <botan/internal/hss.h>
11#include <botan/internal/fmt.h>
12#include <botan/internal/hss_lms_utils.h>
13#include <botan/internal/int_utils.h>
14#include <botan/internal/scan_name.h>
15#include <botan/internal/stl_util.h>
38constexpr uint16_t SEED_CHILD_SEED = 0xfffe;
45constexpr uint16_t SEED_CHILD_I = 0xffff;
50constexpr bool is_supported_hash_function(std::string_view hash_name) {
51 return hash_name ==
"SHA-256" || hash_name ==
"Truncated(SHA-256,192)" || hash_name ==
"SHAKE-256(256)" ||
52 hash_name ==
"SHAKE-256(192)";
59std::vector<LMS_Tree_Node_Idx> derive_lms_leaf_indices_from_hss_index(
HSS_Sig_Idx hss_idx,
60 const HSS_LMS_Params& hss_params) {
61 std::vector<LMS_Tree_Node_Idx> q(hss_params.L().get());
62 for(int32_t layer_ctr = hss_params.L().get() - 1; layer_ctr >= 0; --layer_ctr) {
64 const HSS_LMS_Params::LMS_LMOTS_Params_Pair& layer_params = hss_params.params_at_level(layer);
65 size_t layer_h = layer_params.lms_params().h();
68 hss_idx = hss_idx >> layer_h;
78 m_lms_lmots_params(std::move(lm_lmots_params)), m_max_sig_count(calc_max_sig_count()) {
79 BOTAN_ARG_CHECK(!m_lms_lmots_params.empty() && m_lms_lmots_params.size() <= HSS_MAX_LEVELS,
80 "Invalid number of levels");
84 const auto wrap_in_hss_lms = [&]() {
85 if(algo_params.starts_with(
"HSS-LMS(")) {
86 return std::string(algo_params);
88 return fmt(
"HSS-LMS({})", algo_params);
94 std::string hash = scan.
arg(0);
95 BOTAN_ARG_CHECK(is_supported_hash_function(hash),
"Supported HSS-LMS hash function");
97 for(
size_t i = 1; i < scan.
arg_count(); ++i) {
104 "Invalid Winternitz parameter");
107 m_max_sig_count = calc_max_sig_count();
110HSS_Sig_Idx HSS_LMS_Params::calc_max_sig_count()
const {
111 uint32_t total_height_counter = 0;
112 for(
HSS_Level level(0); level <
L(); level++) {
115 if(total_height_counter >=
sizeof(
HSS_Sig_Idx) * 8) {
116 return HSS_Sig_Idx(std::numeric_limits<HSS_Sig_Idx::wrapped_type>::max());
122 m_hss_params(hss_params), m_current_idx(0), m_sig_size(
HSS_Signature::size(m_hss_params)) {
128 std::span<const uint8_t> key_bytes) {
135 if(L == 0U || L > HSS_MAX_LEVELS) {
136 throw Decoding_Error(
"Invalid number of HSS layers in private HSS-LMS key.");
141 std::vector<HSS_LMS_Params::LMS_LMOTS_Params_Pair> params;
142 for(
size_t layer = 1; layer <= L; ++layer) {
144 throw Decoding_Error(
"Out of bytes while parsing private HSS-LMS key.");
150 std::string hash_name = params.at(0).lms_params().hash_name();
152 bool invalid_lmots_hash = lms_lmots_params.lmots_params().hash_name() != hash_name;
153 bool invalid_lms_hash = lms_lmots_params.lms_params().hash_name() != hash_name;
154 return invalid_lmots_hash || invalid_lms_hash;
156 throw Decoding_Error(
"Inconsistent hash functions are not allowed.");
160 throw Decoding_Error(
"Out of bytes while parsing private HSS-LMS key.");
162 auto hss_seed = slicer.
copy<
LMS_Seed>(params.at(0).lms_params().m());
165 if(!slicer.
empty()) {
166 throw Decoding_Error(
"Private HSS-LMS key contains more bytes than expected.");
168 auto sk = std::shared_ptr<HSS_LMS_PrivateKeyInternal>(
171 sk->set_idx(sig_idx);
187 stuffer.
append(m_hss_seed);
188 stuffer.
append(m_identifier);
198HSS_Sig_Idx HSS_LMS_PrivateKeyInternal::reserve_next_idx() {
207size_t HSS_LMS_PrivateKeyInternal::size()
const {
211 sk_size += m_hss_seed.size() + m_identifier.size();
218 m_hss_params(std::move(hss_params)),
219 m_hss_seed(std::move(hss_seed)),
220 m_identifier(std::move(identifier)),
222 m_sig_size(HSS_Signature::size(m_hss_params)) {
224 "Invalid seed size");
233 std::vector<LMS_Tree_Node_Idx> q = derive_lms_leaf_indices_from_hss_index(reserve_next_idx(),
hss_params());
236 std::vector<LMS_PrivateKey> lms_key_at_layer;
237 std::vector<StrongSpan<LMS_Signature_Bytes>> out_lms_sig_buffer_at_layer;
238 std::vector<std::span<uint8_t>> out_child_pk_buffer_at_layer;
245 lms_key_at_layer.push_back(
246 hss_derive_child_lms_private_key(layer_params, lms_key_at_layer.back(), q.at(layer.get() - 1)));
255 std::vector<uint8_t> current_pk;
256 for(int32_t layer_it =
hss_params().L().get() - 1; layer_it >= 0; --layer_it) {
260 lms_key_at_layer.at(layer.
get())
261 .sign_and_get_pk(out_lms_sig_buffer_at_layer.at(layer.
get()), q.at(layer.
get()),
LMS_Message(msg))
264 copy_mem(out_child_pk_buffer_at_layer.at(layer.
get()), current_pk);
266 lms_key_at_layer.at(layer.
get())
267 .sign_and_get_pk(out_lms_sig_buffer_at_layer.at(layer.
get()), q.at(layer.
get()),
LMS_Message(current_pk))
277 return LMS_PrivateKey(top_params.lms_params(), top_params.lmots_params(), m_identifier, m_hss_seed);
280LMS_PrivateKey HSS_LMS_PrivateKeyInternal::hss_derive_child_lms_private_key(
288 seed_generator.set_q(parent_q.
get());
289 seed_generator.set_i(SEED_CHILD_SEED);
290 seed_generator.set_j(0xff);
291 auto child_seed = seed_generator.gen<
LMS_Seed>(*hash, parent_sk.
seed());
294 seed_generator.set_i(SEED_CHILD_I);
301 std::move(child_identifier),
302 std::move(child_seed));
315 std::span<const uint8_t> key_bytes) {
316 if(key_bytes.size() <
sizeof(
HSS_Level)) {
322 if(L > HSS_MAX_LEVELS) {
323 throw Decoding_Error(
"Invalid number of HSS layers in public HSS-LMS key.");
328 if(!slicer.
empty()) {
329 throw Decoding_Error(
"Public HSS-LMS key contains more bytes than expected.");
331 return std::make_shared<HSS_LMS_PublicKeyInternal>(L, std::move(
lms_pub_key));
378 m_sig(std::move(sig)), m_pub(std::move(pub)) {}
381 if(sig_bytes.size() <
sizeof(uint32_t)) {
387 if(
Nspk >= HSS_MAX_LEVELS) {
388 throw Decoding_Error(
"Invalid number of HSS layers in signature.");
391 std::vector<Signed_Pub_Key> signed_pub_keys;
392 for(
size_t i = 0; i <
Nspk; ++i) {
395 signed_pub_keys.push_back(
Signed_Pub_Key(std::move(sig), std::move(pub_key)));
400 if(!slicer.
empty()) {
401 throw Decoding_Error(
"HSS-LMS signature contains more bytes than expected.");
403 return HSS_Signature(std::move(signed_pub_keys), std::move(sig));
407 size_t size =
sizeof(uint32_t);
410 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_Sig_Idx max_sig_count() const
The maximal number of signatures allowed for these HSS parameters.
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.
HSS_Sig_Idx get_idx() const
Get the idx of the next signature to generate.
void set_idx(HSS_Sig_Idx idx)
Set the idx of the next signature to generate.
std::vector< uint8_t > sign(std::span< const uint8_t > msg)
Create a HSS-LMS signature.
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.
HSS_LMS_PrivateKeyInternal(const HSS_LMS_Params &hss_params, RandomNumberGenerator &rng)
Create an internal HSS-LMS private key.
The internal HSS-LMS public key.
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...
void random_vec(std::span< uint8_t > v)
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
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 RT checked_cast_to_or_throw(AT i, std::string_view error_msg_on_fail)
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_Identifier_ > LMS_Identifier
The identifier of an LMS tree (I in RFC 8554)
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.
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.
std::vector< T, secure_allocator< T > > secure_vector
constexpr void copy_mem(T *out, const T *in, size_t n)
constexpr auto store_be(ParamTs &&... params)
constexpr auto load_be(ParamTs &&... params)