diff --git a/src/lib/pubkey/hss_lms/hss.cpp b/src/lib/pubkey/hss_lms/hss.cpp index fc2bd38223c..a6b24efae96 100644 --- a/src/lib/pubkey/hss_lms/hss.cpp +++ b/src/lib/pubkey/hss_lms/hss.cpp @@ -101,18 +101,18 @@ HSS_LMS_Params::HSS_LMS_Params(std::string_view algo_params) { } HSS_Sig_Idx HSS_LMS_Params::calc_max_sig_count() const { - uint32_t total_hight_counter = 0; + uint32_t total_height_counter = 0; for(HSS_Level level(0); level < L(); level++) { - total_hight_counter += params_at_level(level).lms_params().h(); + total_height_counter += params_at_level(level).lms_params().h(); } - if(total_hight_counter >= sizeof(HSS_Sig_Idx) * 8) { + if(total_height_counter >= sizeof(HSS_Sig_Idx) * 8) { return HSS_Sig_Idx(std::numeric_limits<HSS_Sig_Idx::wrapped_type>::max()); } - return HSS_Sig_Idx(1) << total_hight_counter; + return HSS_Sig_Idx(1) << total_height_counter; } HSS_LMS_PrivateKeyInternal::HSS_LMS_PrivateKeyInternal(const HSS_LMS_Params& hss_params, RandomNumberGenerator& rng) : - m_hss_params(hss_params), m_current_idx(0) { + m_hss_params(hss_params), m_current_idx(0), m_sig_size(HSS_Signature::size(m_hss_params)) { m_hss_seed = rng.random_vec<LMS_Seed>(m_hss_params.params_at_level(HSS_Level(0)).lms_params().m()); m_identifier = rng.random_vec<LMS_Identifier>(LMS_IDENTIFIER_LEN); } @@ -211,7 +211,8 @@ HSS_LMS_PrivateKeyInternal::HSS_LMS_PrivateKeyInternal(HSS_LMS_Params hss_params m_hss_params(std::move(hss_params)), m_hss_seed(std::move(hss_seed)), m_identifier(std::move(identifier)), - m_current_idx(0) { + m_current_idx(0), + m_sig_size(HSS_Signature::size(m_hss_params)) { BOTAN_ARG_CHECK(m_hss_seed.size() == m_hss_params.params_at_level(HSS_Level(0)).lms_params().m(), "Invalid seed size"); BOTAN_ARG_CHECK(m_identifier.size() == LMS_IDENTIFIER_LEN, "Invalid identifier size"); diff --git a/src/lib/pubkey/hss_lms/hss.h b/src/lib/pubkey/hss_lms/hss.h index d37b00ce339..f927a781cd0 100644 --- a/src/lib/pubkey/hss_lms/hss.h +++ b/src/lib/pubkey/hss_lms/hss.h @@ -188,6 +188,11 @@ class BOTAN_TEST_API HSS_LMS_PrivateKeyInternal final { */ LMS_PrivateKey hss_derive_root_lms_private_key() const; + /** + * @brief Returns the size in bytes of a signature created by this key. + */ + size_t signature_size() const { return m_sig_size; }; + private: HSS_LMS_PrivateKeyInternal(HSS_LMS_Params hss_params, LMS_Seed hss_seed, LMS_Identifier identifier); @@ -221,6 +226,7 @@ class BOTAN_TEST_API HSS_LMS_PrivateKeyInternal final { LMS_Seed m_hss_seed; LMS_Identifier m_identifier; HSS_Sig_Idx m_current_idx; + const size_t m_sig_size; }; class HSS_Signature; diff --git a/src/lib/pubkey/hss_lms/hss_lms.cpp b/src/lib/pubkey/hss_lms/hss_lms.cpp index 48a9cc76d85..08b8eaf89d5 100644 --- a/src/lib/pubkey/hss_lms/hss_lms.cpp +++ b/src/lib/pubkey/hss_lms/hss_lms.cpp @@ -169,7 +169,7 @@ class HSS_LMS_Signature_Operation final : public PK_Ops::Signature { return m_private->sign(message_to_sign); } - size_t signature_length() const override { return HSS_Signature::size(m_private->hss_params()); } + size_t signature_length() const override { return m_private->signature_size(); } AlgorithmIdentifier algorithm_identifier() const override { return m_public->algorithm_identifier(); } diff --git a/src/lib/pubkey/hss_lms/hss_lms.h b/src/lib/pubkey/hss_lms/hss_lms.h index fd3e5140596..8b6f3bb5b3c 100644 --- a/src/lib/pubkey/hss_lms/hss_lms.h +++ b/src/lib/pubkey/hss_lms/hss_lms.h @@ -31,7 +31,7 @@ class HSS_LMS_PrivateKeyInternal; * To derive seeds for single LMS trees in the HSS-multitree, the method (SECRET_METHOD 2) * of the reference implementation (https://github.com/cisco/hash-sigs) is used. */ -class BOTAN_PUBLIC_API(3, 2) HSS_LMS_PublicKey : public virtual Public_Key { +class BOTAN_PUBLIC_API(3, 4) HSS_LMS_PublicKey : public virtual Public_Key { public: /** * @brief Load an existing public key using its bytes. @@ -112,7 +112,7 @@ BOTAN_DIAGNOSTIC_IGNORE_INHERITED_VIA_DOMINANCE * * Note: The selected hash function is also used for seed derivation. */ -class BOTAN_PUBLIC_API(3, 2) HSS_LMS_PrivateKey final : public virtual HSS_LMS_PublicKey, +class BOTAN_PUBLIC_API(3, 4) HSS_LMS_PrivateKey final : public virtual HSS_LMS_PublicKey, public virtual Private_Key { public: /** diff --git a/src/lib/pubkey/hss_lms/lm_ots.cpp b/src/lib/pubkey/hss_lms/lm_ots.cpp index 87ab8b0db53..42bd1f455cc 100644 --- a/src/lib/pubkey/hss_lms/lm_ots.cpp +++ b/src/lib/pubkey/hss_lms/lm_ots.cpp @@ -57,8 +57,11 @@ uint8_t byte(std::span<const uint8_t> S, uint32_t i) { // RFC 8554 3.1.3 uint8_t coef(std::span<const uint8_t> S, uint32_t i, const LMOTS_Params& params) { - return params.coef_max() & - (byte(S, (i * params.w()) / 8) >> (8 - (params.w() * (i % (8 / params.w())) + params.w()))); + const uint8_t w_bit_mask = params.coef_max(); + const uint8_t coef_byte = byte(S, (i * params.w()) / 8); + const uint8_t shift = 8 - (params.w() * (i % (8 / params.w())) + params.w()); + + return w_bit_mask & (coef_byte >> shift); } // RFC 8554 4.4 @@ -77,7 +80,7 @@ std::vector<uint8_t> gen_Q_with_cksm(const LMOTS_Params& params, const LMS_Message& msg) { std::vector<uint8_t> Q_with_cksm(params.n() + sizeof(uint16_t)); BufferStuffer qwc_stuffer(Q_with_cksm); - const auto hash = HashFunction::create_or_throw(params.hash_name()); + const auto hash = params.hash(); hash->update(identifier); hash->update(store_be(q)); hash->update(store_be(D_MESG)); @@ -258,7 +261,7 @@ LMOTS_Private_Key::LMOTS_Private_Key(const LMOTS_Params& params, const LMS_Seed& seed) : OTS_Instance(params, identifier, q), m_seed(seed) { PseudorandomKeyGeneration gen(identifier); - const auto hash = HashFunction::create_or_throw(params.hash_name()); + const auto hash = params.hash(); gen.set_q(q.get()); gen.set_j(0xff); @@ -272,7 +275,7 @@ LMOTS_Private_Key::LMOTS_Private_Key(const LMOTS_Params& params, void LMOTS_Private_Key::sign(StrongSpan<LMOTS_Signature_Bytes> out_sig, const LMS_Message& msg) const { BOTAN_ARG_CHECK(out_sig.size() == LMOTS_Signature::size(params()), "Invalid output buffer size"); BufferStuffer sig_stuffer(out_sig); - const auto hash = HashFunction::create_or_throw(params().hash_name()); + const auto hash = params().hash(); sig_stuffer.append(store_be(params().algorithm_type())); const auto C = sig_stuffer.next(params().n()); @@ -303,13 +306,13 @@ void LMOTS_Private_Key::derive_random_C(std::span<uint8_t> out, HashFunction& ha } LMOTS_Public_Key::LMOTS_Public_Key(const LMOTS_Private_Key& lmots_sk) : OTS_Instance(lmots_sk) { - const auto pk_hash = HashFunction::create_or_throw(lmots_sk.params().hash_name()); + const auto pk_hash = lmots_sk.params().hash(); pk_hash->update(lmots_sk.identifier()); pk_hash->update(store_be(lmots_sk.q())); pk_hash->update(store_be(D_PBLC)); Chain_Generator chain_gen(lmots_sk.identifier(), lmots_sk.q()); - const auto hash = HashFunction::create_or_throw(lmots_sk.params().hash_name()); + const auto hash = lmots_sk.params().hash(); LMOTS_Node tmp(lmots_sk.params().n()); for(uint16_t i = 0; i < lmots_sk.params().p(); ++i) { chain_gen.process(*hash, i, 0, lmots_sk.params().coef_max(), lmots_sk.chain_input(i), tmp); @@ -330,13 +333,13 @@ LMOTS_K lmots_compute_pubkey_from_sig(const LMOTS_Signature& sig, const auto Q_with_cksm = gen_Q_with_cksm(params, identifier, q, sig.C(), msg); // Prefill the final hash object - const auto pk_hash = HashFunction::create_or_throw(params.hash_name()); + const auto pk_hash = params.hash(); pk_hash->update(identifier); pk_hash->update(store_be(q)); pk_hash->update(store_be(D_PBLC)); Chain_Generator chain_gen(identifier, q); - const auto hash = HashFunction::create_or_throw(params.hash_name()); + const auto hash = params.hash(); LMOTS_Node tmp(params.n()); for(uint16_t i = 0; i < params.p(); ++i) { const uint8_t a = coef(Q_with_cksm, i, params); diff --git a/src/lib/pubkey/hss_lms/lm_ots.h b/src/lib/pubkey/hss_lms/lm_ots.h index f781c4178b6..596f4ec3d19 100644 --- a/src/lib/pubkey/hss_lms/lm_ots.h +++ b/src/lib/pubkey/hss_lms/lm_ots.h @@ -149,6 +149,11 @@ class BOTAN_TEST_API LMOTS_Params { */ const std::string& hash_name() const { return m_hash_name; } + /** + * @brief Construct a new hash instance for the OTS instance. + */ + std::unique_ptr<HashFunction> hash() const { return HashFunction::create_or_throw(hash_name()); } + private: /** * @brief Construct a new LM-OTS parameter object. diff --git a/src/lib/pubkey/hss_lms/lms.cpp b/src/lib/pubkey/hss_lms/lms.cpp index d05a32cc4eb..a955c41cf09 100644 --- a/src/lib/pubkey/hss_lms/lms.cpp +++ b/src/lib/pubkey/hss_lms/lms.cpp @@ -55,11 +55,10 @@ class TreeAddress final { }; auto get_hash_pair_func_for_identifier(const LMS_Params& lms_params, LMS_Identifier identifier) { - return [hash = HashFunction::create_or_throw(lms_params.hash_name()), I = std::move(identifier)]( - StrongSpan<LMS_Tree_Node> out, - const TreeAddress& address, - StrongSpan<const LMS_Tree_Node> left, - StrongSpan<const LMS_Tree_Node> right) { + return [hash = lms_params.hash(), I = std::move(identifier)](StrongSpan<LMS_Tree_Node> out, + const TreeAddress& address, + StrongSpan<const LMS_Tree_Node> left, + StrongSpan<const LMS_Tree_Node> right) { auto lms_address = dynamic_cast<const TreeAddress&>(address); hash->update(I); @@ -83,8 +82,7 @@ void lms_gen_leaf(StrongSpan<LMS_Tree_Node> out, } auto lms_gen_leaf_func(const LMS_PrivateKey& lms_sk) { - return [hash = HashFunction::create_or_throw(lms_sk.lms_params().hash_name()), lms_sk]( - StrongSpan<LMS_Tree_Node> out, const TreeAddress& tree_address) { + return [hash = lms_sk.lms_params().hash(), lms_sk](StrongSpan<LMS_Tree_Node> out, const TreeAddress& tree_address) { auto lmots_sk = LMOTS_Private_Key(lms_sk.lmots_params(), lms_sk.identifier(), tree_address.q(), lms_sk.seed()); auto lmots_pk = LMOTS_Public_Key(lmots_sk); lms_gen_leaf(out, lmots_pk, tree_address, *hash); @@ -165,9 +163,6 @@ LMS_Params LMS_Params::create_or_throw(LMS_Algorithm_Type type) { } LMS_Params LMS_Params::create_or_throw(std::string_view hash_name, uint8_t height) { - if(height != 5 && height != 10 && height != 15 && height != 20 && height != 25) { - throw Decoding_Error("Invalid height"); - } LMS_Algorithm_Type type = [](std::string_view hash, uint8_t h) -> LMS_Algorithm_Type { if(hash == "SHA-256") { switch(h) { @@ -278,7 +273,7 @@ LMS_PublicKey LMS_PublicKey::from_bytes_or_throw(BufferSlicer& slicer) { // Alg. 6. 2.c. auto lms_params = LMS_Params::create_or_throw(lms_type); // Alg. 6. 2.d. - if(total_remaining_bytes < size(lms_params)) { + if(total_remaining_bytes < LMS_PublicKey::size(lms_params)) { throw Decoding_Error("Too few bytes while parsing LMS public key."); } // Alg. 6. 2.b. @@ -397,7 +392,7 @@ std::optional<LMS_Tree_Node> LMS_PublicKey::lms_compute_root_from_sig(const LMS_ const LMOTS_Signature& lmots_sig = sig.lmots_sig(); const LMOTS_Params lmots_params = LMOTS_Params::create_or_throw(lmots_sig.algorithm_type()); const LMOTS_K Kc = lmots_compute_pubkey_from_sig(lmots_sig, msg, identifier(), sig.q()); - const auto hash = HashFunction::create_or_throw(lms_params.hash_name()); + const auto hash = lms_params.hash(); auto hash_pair_func = get_hash_pair_func_for_identifier(lms_params, identifier()); diff --git a/src/lib/pubkey/hss_lms/lms.h b/src/lib/pubkey/hss_lms/lms.h index 468bcace615..52587e46f6a 100644 --- a/src/lib/pubkey/hss_lms/lms.h +++ b/src/lib/pubkey/hss_lms/lms.h @@ -122,6 +122,11 @@ class BOTAN_TEST_API LMS_Params { */ const std::string& hash_name() const { return m_hash_name; } + /** + * @brief Construct a new hash instance for the LMS instance. + */ + std::unique_ptr<HashFunction> hash() const { return HashFunction::create_or_throw(hash_name()); } + private: /** * @brief Construct a new LMS parameter object.