• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 11844561993

14 Nov 2024 07:58PM UTC coverage: 91.178% (+0.1%) from 91.072%
11844561993

Pull #4435

github

web-flow
Merge 81dcb29da into e430f157a
Pull Request #4435: Test duration values ​​are now presented in seconds with six digits of precision. Tests without time measurements have been edited.

91856 of 100744 relevant lines covered (91.18%)

9311006.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.02
/src/tests/test_hss_lms.cpp
1
/*
2
* (C) 2023 Jack Lloyd
3
*     2023 Fabian Albert, Philippe Lieser - Rohde & Schwarz Cybersecurity
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include "test_pubkey.h"
9
#include "tests.h"
10

11
#if defined(BOTAN_HAS_HSS_LMS)
12

13
   #include <botan/hss_lms.h>
14
   #include <botan/pk_algs.h>
15
   #include <botan/internal/fmt.h>
16
   #include <botan/internal/hss.h>
17
   #include <botan/internal/loadstor.h>
18

19
namespace Botan_Tests {
20

21
namespace {
22

23
/**
24
 * @brief Test the correct parsing of HSS-LMS parameters
25
 */
26
std::vector<Test::Result> test_hss_lms_params_parsing() {
1✔
27
   return {
1✔
28
      CHECK("HSS Parameter Parsing",
29
            [&](Test::Result& result) {
1✔
30
               result.start_timer();
1✔
31
               result.test_no_throw("no throw", [&] {
2✔
32
                  Botan::HSS_LMS_Params hss_params("SHA-256,HW(5,1),HW(25,8)");
1✔
33

34
                  result.test_is_eq("hss levels", hss_params.L(), Botan::HSS_Level(2));
1✔
35
                  auto& top_lms_params = hss_params.params_at_level(Botan::HSS_Level(0));
1✔
36
                  result.test_is_eq("hash name", top_lms_params.lms_params().hash_name(), std::string("SHA-256"));
2✔
37
                  result.test_is_eq("top level - lms type",
1✔
38
                                    top_lms_params.lms_params().algorithm_type(),
1✔
39
                                    Botan::LMS_Algorithm_Type::SHA256_M32_H5);
1✔
40
                  result.test_is_eq("top level - ots type",
1✔
41
                                    top_lms_params.lmots_params().algorithm_type(),
1✔
42
                                    Botan::LMOTS_Algorithm_Type::SHA256_N32_W1);
1✔
43

44
                  auto& second_lms_params = hss_params.params_at_level(Botan::HSS_Level(1));
1✔
45
                  result.test_is_eq("2nd level - lms type",
1✔
46
                                    second_lms_params.lms_params().algorithm_type(),
1✔
47
                                    Botan::LMS_Algorithm_Type::SHA256_M32_H25);
1✔
48
                  result.test_is_eq("2nd level - ots type",
1✔
49
                                    second_lms_params.lmots_params().algorithm_type(),
1✔
50
                                    Botan::LMOTS_Algorithm_Type::SHA256_N32_W8);
2✔
51
               });
1✔
52
               result.end_timer();
1✔
53
            }),
1✔
54

55
   };
2✔
56
}
1✔
57

58
/**
59
 * @brief Test signature generation using the raw private key bytes
60
 */
61
class HSS_LMS_Signature_Generation_Test final : public PK_Signature_Generation_Test {
62
   public:
63
      HSS_LMS_Signature_Generation_Test() :
1✔
64
            PK_Signature_Generation_Test("HSS-LMS", "pubkey/hss_lms_sig.vec", "Msg,PrivateKey,Signature") {}
2✔
65

66
      std::string default_padding(const VarMap&) const final { return ""; }
2✔
67

68
      std::unique_ptr<Botan::Private_Key> load_private_key(const VarMap& vars) final {
2✔
69
         const auto sk_bytes = Botan::lock(vars.get_req_bin("PrivateKey"));
6✔
70
         return std::make_unique<Botan::HSS_LMS_PrivateKey>(sk_bytes);
2✔
71
      }
2✔
72
};
73

74
/**
75
 * @brief Test signature verification using the raw public key bytes
76
 */
77
class HSS_LMS_Signature_Verify_Tests final : public PK_Signature_Verification_Test {
78
   public:
79
      HSS_LMS_Signature_Verify_Tests() :
1✔
80
            PK_Signature_Verification_Test("HSS-LMS", "pubkey/hss_lms_verify.vec", "Msg,PublicKey,Signature") {}
2✔
81

82
      std::string default_padding(const VarMap&) const final { return ""; }
5✔
83

84
      std::unique_ptr<Botan::Public_Key> load_public_key(const VarMap& vars) override {
5✔
85
         const std::vector<uint8_t> pk_bytes = vars.get_req_bin("PublicKey");
5✔
86
         return std::make_unique<Botan::HSS_LMS_PublicKey>(pk_bytes);
10✔
87
      }
5✔
88
};
89

90
/**
91
 * @brief Test the correct revocation of invalid signatures
92
 */
93
class HSS_LMS_Signature_Verify_Invalid_Tests final : public PK_Signature_NonVerification_Test {
94
   public:
95
      HSS_LMS_Signature_Verify_Invalid_Tests() :
1✔
96
            PK_Signature_NonVerification_Test(
97
               "HSS_LMS", "pubkey/hss_lms_invalid.vec", "Msg,PublicKey,InvalidSignature") {}
2✔
98

99
      std::string default_padding(const VarMap&) const override { return ""; }
4✔
100

101
      std::unique_ptr<Botan::Public_Key> load_public_key(const VarMap& vars) override {
4✔
102
         const std::vector<uint8_t> raw_key = vars.get_req_bin("PublicKey");
4✔
103
         return std::make_unique<Botan::HSS_LMS_PublicKey>(raw_key);
8✔
104
      }
4✔
105
};
106

107
/**
108
 * @brief Test HSS-LMS public key creation
109
 */
110
class HSS_LMS_Key_Generation_Test final : public PK_Key_Generation_Test {
×
111
   public:
112
      std::vector<std::string> keygen_params() const final { return {"SHA-256,HW(10,4),HW(5,8)"}; }
1✔
113

114
      std::string algo_name() const final { return "HSS-LMS"; }
1✔
115

116
      std::unique_ptr<Botan::Public_Key> public_key_from_raw(std::string_view /* keygen_params */,
1✔
117
                                                             std::string_view /* provider */,
118
                                                             std::span<const uint8_t> raw_pk) const override {
119
         return std::make_unique<Botan::HSS_LMS_PublicKey>(raw_pk);
1✔
120
      }
121
};
122

123
/**
124
 * @brief Test that for manipulated signatures and too short signatures, private keys, and public keys a DecodeError occurs.
125
 */
126
class HSS_LMS_Negative_Tests final : public Test {
×
127
      Test::Result test_flipped_signature_bits() {
1✔
128
         Test::Result result("HSS-LMS - flipped signature bits");
1✔
129
         result.start_timer();
1✔
130

131
         auto sk = Botan::create_private_key("HSS-LMS", Test::rng(), "Truncated(SHA-256,192),HW(5,8)");
1✔
132

133
         Botan::PK_Signer signer(*sk, Test::rng(), "");
1✔
134
         Botan::PK_Verifier verifier(*sk, "");
1✔
135

136
         std::vector<uint8_t> mes = {0xde, 0xad, 0xbe, 0xef};
1✔
137

138
         signer.update(mes);
1✔
139
         auto valid_sig = signer.signature(Test::rng());
1✔
140
         verifier.update(mes);
1✔
141
         result.confirm("Entire signature is valid", verifier.check_signature(valid_sig.data(), valid_sig.size()));
2✔
142
         for(size_t idx = 0; idx < valid_sig.size(); ++idx) {
785✔
143
            auto bad_sig = valid_sig;
784✔
144
            bad_sig.at(idx) ^= 0x80;
784✔
145
            result.test_no_throw(Botan::fmt("Verification does not throw (byte idx {})", idx), [&]() {
2,352✔
146
               verifier.update(mes);
784✔
147
               bool valid = verifier.check_signature(bad_sig);
784✔
148
               result.confirm(Botan::fmt("Manipulated signature is invalid (byte idx {})", idx), !valid);
1,568✔
149
            });
784✔
150
         }
784✔
151

152
         result.end_timer();
1✔
153
         return result;
1✔
154
      }
3✔
155

156
      Test::Result test_too_short_signature() {
1✔
157
         Test::Result result("HSS-LMS");
1✔
158
         result.start_timer();
1✔
159

160
         auto sk = Botan::create_private_key("HSS-LMS", Test::rng(), "Truncated(SHA-256,192),HW(5,8)");
1✔
161

162
         Botan::PK_Signer signer(*sk, Test::rng(), "");
1✔
163
         Botan::PK_Verifier verifier(*sk, "");
1✔
164

165
         std::vector<uint8_t> mes = {0xde, 0xad, 0xbe, 0xef};
1✔
166

167
         signer.update(mes);
1✔
168
         auto valid_sig = signer.signature(Test::rng());
1✔
169
         verifier.update(mes);
1✔
170
         result.confirm("Entire signature is valid", verifier.check_signature(valid_sig.data(), valid_sig.size()));
2✔
171
         for(size_t n = 0; n < valid_sig.size(); ++n) {
785✔
172
            result.test_no_throw("Verification does not throw", [&]() {
2,352✔
173
               verifier.update(mes);
784✔
174
               bool valid = verifier.check_signature(valid_sig.data(), n);
784✔
175
               result.confirm("Too short signature is invalid", !valid);
1,568✔
176
            });
784✔
177
         }
178

179
         result.end_timer();
1✔
180
         return result;
1✔
181
      }
3✔
182

183
      Test::Result test_too_short_private_key() {
1✔
184
         Test::Result result("HSS-LMS");
1✔
185
         result.start_timer();
1✔
186

187
         // HSS_LMS_PublicKey::key_length()
188
         auto sk = Botan::create_private_key("HSS-LMS", Test::rng(), "Truncated(SHA-256,192),HW(5,8)");
1✔
189

190
         auto sk_bytes = sk->private_key_bits();
1✔
191
         result.test_no_throw("Entire private key valid", [&]() {
2✔
192
            Botan::HSS_LMS_PrivateKey key(sk_bytes);
1✔
193
            BOTAN_UNUSED(key);
1✔
194
         });
1✔
195
         for(size_t n = 0; n < sk_bytes.size(); ++n) {
61✔
196
            result.test_throws<Botan::Decoding_Error>("Partial private key invalid", [&]() {
180✔
197
               std::span<const uint8_t> partial_key = {sk_bytes.data(), n};
60✔
198
               Botan::HSS_LMS_PrivateKey key(partial_key);
60✔
199
               BOTAN_UNUSED(key);
×
200
            });
×
201
         }
202

203
         result.end_timer();
1✔
204
         return result;
1✔
205
      }
2✔
206

207
      Test::Result test_too_short_public_key() {
1✔
208
         Test::Result result("HSS-LMS");
1✔
209
         result.start_timer();
1✔
210

211
         // HSS_LMS_PublicKey::key_length()
212
         auto sk = Botan::create_private_key("HSS-LMS", Test::rng(), "Truncated(SHA-256,192),HW(5,8)");
1✔
213

214
         auto sk_bytes = sk->public_key_bits();
1✔
215
         result.test_no_throw("Entire public key valid", [&]() {
2✔
216
            Botan::HSS_LMS_PublicKey key(sk_bytes);
1✔
217
            BOTAN_UNUSED(key);
1✔
218
         });
1✔
219
         for(size_t n = 0; n < sk_bytes.size(); ++n) {
53✔
220
            result.test_throws<Botan::Decoding_Error>("Partial public key invalid", [&]() {
156✔
221
               std::span<const uint8_t> partial_key = {sk_bytes.data(), n};
52✔
222
               Botan::HSS_LMS_PublicKey key(partial_key);
52✔
223
               BOTAN_UNUSED(key);
×
224
            });
×
225
         }
226

227
         result.end_timer();
1✔
228
         return result;
1✔
229
      }
2✔
230

231
      std::vector<Test::Result> run() final {
1✔
232
         return {test_flipped_signature_bits(),
1✔
233
                 test_too_short_signature(),
234
                 test_too_short_private_key(),
235
                 test_too_short_public_key()};
5✔
236
      }
1✔
237
};
238

239
/**
240
 * @brief Test the correct handling of the HSS-LMS private key's state.
241
 */
242
class HSS_LMS_Statefulness_Test final : public Test {
×
243
      Botan::HSS_LMS_PrivateKey create_private_key_with_idx(uint64_t idx) {
1✔
244
         auto sk = Botan::HSS_LMS_PrivateKey(Test::rng(), "Truncated(SHA-256,192),HW(5,8)");
1✔
245
         auto bytes = sk.private_key_bits();
1✔
246
         // The index is store after the level (uint32_t)
247
         Botan::store_be(idx, bytes.data() + sizeof(uint32_t));
1✔
248
         return Botan::HSS_LMS_PrivateKey(bytes);
2✔
249
      }
1✔
250

251
      Test::Result test_sig_changes_state() {
1✔
252
         Test::Result result("HSS-LMS");
1✔
253
         result.start_timer();
1✔
254

255
         auto sk = Botan::HSS_LMS_PrivateKey(Test::rng(), "Truncated(SHA-256,192),HW(5,8),HW(5,8)");
1✔
256
         Botan::PK_Signer signer(sk, Test::rng(), "");
1✔
257
         std::vector<uint8_t> mes = {0xde, 0xad, 0xbe, 0xef};
1✔
258
         auto sk_bytes_begin = sk.private_key_bits();
1✔
259

260
         // Tree hights: 5,5 => 2^(5+5) = 1024 signatures available
261
         const uint64_t expected_total = 1024;
1✔
262
         result.confirm("Fresh key starts with total number of remaining signatures.",
1✔
263
                        sk.remaining_operations() == expected_total);
2✔
264

265
         // Creating a signature should update the private key's state
266
         auto sig_0 = signer.sign_message(mes, Test::rng());
1✔
267
         result.confirm(
2✔
268
            "First signature uses index 0.",
269
            Botan::HSS_Signature::from_bytes_or_throw(sig_0).bottom_sig().q() == Botan::LMS_Tree_Node_Idx(0));
1✔
270

271
         auto sk_bytes_after_sig = sk.private_key_bits();
1✔
272

273
         result.confirm("Signature decreases number of remaining signatures.",
1✔
274
                        sk.remaining_operations() == expected_total - 1);
2✔
275
         result.test_ne("Signature updates private key.", sk_bytes_after_sig, sk_bytes_begin);
2✔
276

277
         auto sig_1 = signer.sign_message(mes, Test::rng());
1✔
278
         result.confirm(
2✔
279
            "Next signature uses the new index.",
280
            Botan::HSS_Signature::from_bytes_or_throw(sig_1).bottom_sig().q() == Botan::LMS_Tree_Node_Idx(1));
1✔
281

282
         result.end_timer();
1✔
283
         return result;
2✔
284
      }
5✔
285

286
      Test::Result test_max_sig_count() {
1✔
287
         Test::Result result("HSS-LMS");
1✔
288
         result.start_timer();
1✔
289

290
         uint64_t total_sig_count = 32;
1✔
291
         auto sk = create_private_key_with_idx(total_sig_count - 1);
1✔
292

293
         Botan::PK_Signer signer(sk, Test::rng(), "");
1✔
294
         std::vector<uint8_t> mes = {0xde, 0xad, 0xbe, 0xef};
1✔
295
         auto sk_bytes_begin = sk.private_key_bits();
1✔
296

297
         result.confirm("One remaining signature.", sk.remaining_operations() == uint64_t(1));
3✔
298
         result.test_no_throw("Use last signature index.", [&]() { signer.sign_message(mes, Test::rng()); });
4✔
299
         result.confirm("No remaining signatures.", sk.remaining_operations() == uint64_t(0));
3✔
300
         result.test_throws("Cannot sign with exhausted key.", [&]() { signer.sign_message(mes, Test::rng()); });
3✔
301
         result.confirm("Still zero remaining signatures.", sk.remaining_operations() == uint64_t(0));
3✔
302

303
         result.end_timer();
1✔
304
         return result;
2✔
305
      }
2✔
306

307
      std::vector<Test::Result> run() final { return {test_sig_changes_state(), test_max_sig_count()}; }
3✔
308
};
309

310
/**
311
 * @brief Test APIs not covered by other tests.
312
 */
313
class HSS_LMS_Missing_API_Test final : public Test {
×
314
      std::vector<Test::Result> run() final {
1✔
315
         Test::Result result("HSS-LMS");
1✔
316
         result.start_timer();
1✔
317

318
         // HSS_LMS_PublicKey::key_length()
319
         auto sk = Botan::create_private_key("HSS-LMS", Test::rng(), "SHA-256,HW(10,4)");
1✔
320
         sk->key_length();
1✔
321
         result.test_gt("Public key length must be greater than the simply type information plus I",
1✔
322
                        sk->key_length(),
1✔
323
                        3 * sizeof(uint32_t) + Botan::LMS_IDENTIFIER_LEN);
324

325
         // HSS_LMS_Verification_Operation::hash_function()
326
         Botan::PK_Verifier verifier(*sk, "");
1✔
327
         result.test_eq("PK_Verifier should report the hash of the key", verifier.hash_function(), "SHA-256");
2✔
328

329
         // HSS_LMS_PrivateKey::raw_private_key_bits()
330
         result.test_eq("Our BER and raw encoding is the same", sk->raw_private_key_bits(), sk->private_key_bits());
3✔
331

332
         // HSS_LMS_Signature_Operation::algorithm_identifier()
333
         Botan::PK_Signer signer(*sk, Test::rng(), "");
1✔
334
         result.test_is_eq(signer.algorithm_identifier(), sk->algorithm_identifier());
1✔
335

336
         // HSS_LMS_Signature_Operation::hash_function()
337
         result.test_eq("PK_Signer should report the hash of the key", signer.hash_function(), "SHA-256");
2✔
338

339
         result.end_timer();
1✔
340
         return {result};
3✔
341
      }
3✔
342
};
343

344
BOTAN_REGISTER_TEST_FN("pubkey", "hss_lms_params_parsing", test_hss_lms_params_parsing);
345
BOTAN_REGISTER_TEST("pubkey", "hss_lms_sign", HSS_LMS_Signature_Generation_Test);
346
BOTAN_REGISTER_TEST("pubkey", "hss_lms_verify", HSS_LMS_Signature_Verify_Tests);
347
BOTAN_REGISTER_TEST("pubkey", "hss_lms_verify_invalid", HSS_LMS_Signature_Verify_Invalid_Tests);
348
BOTAN_REGISTER_TEST("pubkey", "hss_lms_keygen", HSS_LMS_Key_Generation_Test);
349
BOTAN_REGISTER_TEST("pubkey", "hss_lms_negative", HSS_LMS_Negative_Tests);
350
BOTAN_REGISTER_TEST("pubkey", "hss_lms_state", HSS_LMS_Statefulness_Test);
351
BOTAN_REGISTER_TEST("pubkey", "hss_lms_api", HSS_LMS_Missing_API_Test);
352

353
}  // namespace
354

355
}  // namespace Botan_Tests
356

357
#endif  // BOTAN_HAS_HSS_LMS
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc