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

randombit / botan / 5356326050

23 Jun 2023 01:05PM UTC coverage: 91.728% (-0.008%) from 91.736%
5356326050

Pull #3595

github

web-flow
Merge a5b917599 into 92171c524
Pull Request #3595: Improve clang-tidy coverage

78163 of 85212 relevant lines covered (91.73%)

12690161.35 hits per line

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

94.92
/src/tests/test_kyber.cpp
1
/*
2
 * Tests for Crystals Kyber
3
 * - simple roundtrip test
4
 * - KAT tests using the KAT vectors from
5
 *   https://csrc.nist.gov/CSRC/media/Projects/post-quantum-cryptography/documents/round-3/submissions/Kyber-Round3.zip
6
 *
7
 * (C) 2021-2022 Jack Lloyd
8
 * (C) 2021-2022 Manuel Glaser and Michael Boric, Rohde & Schwarz Cybersecurity
9
 * (C) 2021-2022 René Meusel and Hannes Rantzsch, neXenio GmbH
10
 *
11
 * Botan is released under the Simplified BSD License (see license.txt)
12
 */
13

14
#include "test_rng.h"
15
#include "tests.h"
16

17
#include <iterator>
18
#include <memory>
19

20
#if defined(BOTAN_HAS_KYBER) || defined(BOTAN_HAS_KYBER_90S)
21
   #include "test_pubkey.h"
22
   #include <botan/hex.h>
23
   #include <botan/kyber.h>
24
   #include <botan/pubkey.h>
25
   #include <botan/rng.h>
26
#endif
27

28
namespace Botan_Tests {
29

30
#if defined(BOTAN_HAS_KYBER) || defined(BOTAN_HAS_KYBER_90S)
31

32
class KYBER_Tests final : public Test {
×
33
   public:
34
      static Test::Result run_kyber_test(const char* test_name, Botan::KyberMode mode, size_t strength) {
6✔
35
         Test::Result result(test_name);
6✔
36

37
         const std::vector<uint8_t> empty_salt;
6✔
38

39
         // Alice
40
         const Botan::Kyber_PrivateKey priv_key(Test::rng(), mode);
6✔
41
         const auto pub_key = priv_key.public_key();
6✔
42

43
         result.test_eq("estimated strength private", priv_key.estimated_strength(), strength);
6✔
44
         result.test_eq("estimated strength public", pub_key->estimated_strength(), strength);
6✔
45

46
         // Serialize
47
         const auto priv_key_bits = priv_key.private_key_bits();
6✔
48
         const auto pub_key_bits = pub_key->public_key_bits();
6✔
49

50
         // Bob (reading from serialized public key)
51
         Botan::Kyber_PublicKey alice_pub_key(pub_key_bits, mode);
6✔
52
         auto enc = Botan::PK_KEM_Encryptor(alice_pub_key, "Raw", "base");
6✔
53
         Botan::secure_vector<uint8_t> cipher_text, key_bob;
6✔
54
         enc.encrypt(cipher_text, key_bob, 0 /* no KDF */, Test::rng());
6✔
55

56
         // Alice (reading from serialized private key)
57
         Botan::Kyber_PrivateKey alice_priv_key(priv_key_bits, mode);
6✔
58
         auto dec = Botan::PK_KEM_Decryptor(alice_priv_key, Test::rng(), "Raw", "base");
6✔
59
         const auto key_alice = dec.decrypt(cipher_text, 0 /* no KDF */, empty_salt);
6✔
60
         result.test_eq("shared secrets are equal", key_alice, key_bob);
6✔
61

62
         //
63
         // negative tests
64
         //
65

66
         // Broken cipher_text from Alice (wrong length)
67
         result.test_throws("fail to read cipher_text", "Kyber: unexpected ciphertext length", [&] {
18✔
68
            auto short_cipher_text = cipher_text;
6✔
69
            short_cipher_text.pop_back();
6✔
70
            dec.decrypt(short_cipher_text, 0, empty_salt);
6✔
71
         });
×
72

73
         // Invalid cipher_text from Alice
74
         Botan::secure_vector<uint8_t> reverse_cipher_text;
6✔
75
         std::copy(cipher_text.crbegin(), cipher_text.crend(), std::back_inserter(reverse_cipher_text));
6✔
76
         const auto key_alice_rev = dec.decrypt(reverse_cipher_text, 0, empty_salt);
6✔
77
         result.confirm("shared secrets are not equal", key_alice != key_alice_rev);
12✔
78

79
         // Try to decrypt the valid ciphertext again
80
         const auto key_alice_try2 = dec.decrypt(cipher_text, 0 /* no KDF */, empty_salt);
6✔
81
         result.test_eq("shared secrets are equal", key_alice_try2, key_bob);
6✔
82

83
         return result;
6✔
84
      }
54✔
85

86
      std::vector<Test::Result> run() override {
1✔
87
         std::vector<Test::Result> results;
1✔
88

89
   #if defined(BOTAN_HAS_KYBER_90S)
90
         results.push_back(run_kyber_test("Kyber512_90s API", Botan::KyberMode::Kyber512_90s, 128));
2✔
91
         results.push_back(run_kyber_test("Kyber768_90s API", Botan::KyberMode::Kyber768_90s, 192));
2✔
92
         results.push_back(run_kyber_test("Kyber1024_90s API", Botan::KyberMode::Kyber1024_90s, 256));
2✔
93
   #endif
94
   #if defined(BOTAN_HAS_KYBER)
95
         results.push_back(run_kyber_test("Kyber512 API", Botan::KyberMode::Kyber512, 128));
2✔
96
         results.push_back(run_kyber_test("Kyber768 API", Botan::KyberMode::Kyber768, 192));
2✔
97
         results.push_back(run_kyber_test("Kyber1024 API", Botan::KyberMode::Kyber1024, 256));
2✔
98
   #endif
99

100
         return results;
1✔
101
      }
×
102
};
103

104
BOTAN_REGISTER_TEST("kyber", "kyber_pairwise", KYBER_Tests);
105

106
   #if defined(BOTAN_HAS_AES)
107

108
namespace {
109

110
Test::Result check_kyber_kat(const char* test_name,
600✔
111
                             const VarMap& vars,
112
                             Botan::KyberMode mode,
113
                             const std::string& algo_name) {
114
   Test::Result result(test_name);
600✔
115

116
   // read input from test file
117
   const auto pk_in = vars.get_req_bin("PK");
600✔
118
   const auto sk_in = vars.get_req_bin("SK");
600✔
119
   const auto ct_in = vars.get_req_bin("CT");
600✔
120
   const auto ss_in = vars.get_req_bin("SS");
600✔
121

122
   // Kyber test RNG
123
   CTR_DRBG_AES256 ctr_drbg(vars.get_req_bin("Seed"));
1,200✔
124

125
   // Alice
126
   Botan::Kyber_PrivateKey priv_key(ctr_drbg, mode);
600✔
127
   const auto pub_key = priv_key.public_key();
600✔
128
   result.test_eq("Public Key Output", priv_key.public_key_bits(), pk_in);
1,200✔
129
   result.test_eq("Secret Key Output", priv_key.private_key_bits(), sk_in);
1,200✔
130

131
   // Bob
132
   auto enc = Botan::PK_KEM_Encryptor(*pub_key, "Raw", "base");
600✔
133
   Botan::secure_vector<uint8_t> cipher_text, key_bob;
600✔
134
   enc.encrypt(cipher_text, key_bob, 0 /* no KDF */, ctr_drbg);
600✔
135
   result.test_eq("Cipher-Text Output", cipher_text, ct_in);
600✔
136
   result.test_eq("Key B Output", key_bob, ss_in);
600✔
137

138
   // Alice
139
   auto dec = Botan::PK_KEM_Decryptor(priv_key, ctr_drbg, "Raw", "base");
600✔
140
   const auto key_alice = dec.decrypt(cipher_text, 0 /* no KDF */, std::vector<uint8_t>());
600✔
141
   result.test_eq("Key A Output", key_alice, ss_in);
600✔
142

143
   // Algorithm identifiers
144
   result.test_eq("algo name", priv_key.algo_name(), algo_name);
1,200✔
145
   result.confirm("algo mode", priv_key.mode() == mode);
1,200✔
146
   result.test_eq("algo id", priv_key.algorithm_identifier().oid().to_formatted_string(), algo_name);
1,500✔
147

148
   return result;
600✔
149
}
5,400✔
150

151
}  // namespace
152

153
      // NOLINTNEXTLINE(*-macro-usage)
154
      #define REGISTER_KYBER_KAT_TEST(mode)                                                                    \
155
         class KYBER_KAT_##mode final : public Text_Based_Test {                                               \
156
            public:                                                                                            \
157
               KYBER_KAT_##mode() : Text_Based_Test("pubkey/kyber_" #mode ".vec", "Count,Seed,PK,SK,CT,SS") {} \
158
                                                                                                               \
159
               Test::Result run_one_test(const std::string& name, const VarMap& vars) override {               \
160
                  return check_kyber_kat("Kyber_" #mode, vars, Botan::KyberMode::Kyber##mode, name);           \
161
               }                                                                                               \
162
         };                                                                                                    \
163
         BOTAN_REGISTER_TEST("kyber", "kyber_kat_" #mode, KYBER_KAT_##mode)
164

165
      #if defined(BOTAN_HAS_KYBER_90S)
166
REGISTER_KYBER_KAT_TEST(512_90s);
103✔
167
REGISTER_KYBER_KAT_TEST(768_90s);
103✔
168
REGISTER_KYBER_KAT_TEST(1024_90s);
103✔
169
      #endif
170

171
      #if defined(BOTAN_HAS_KYBER)
172
REGISTER_KYBER_KAT_TEST(512);
103✔
173
REGISTER_KYBER_KAT_TEST(768);
103✔
174
REGISTER_KYBER_KAT_TEST(1024);
101✔
175
      #endif
176

177
      #undef REGISTER_KYBER_KAT_TEST
178

179
   #endif
180

181
class Kyber_Encoding_Test : public Text_Based_Test {
182
   public:
183
      Kyber_Encoding_Test() : Text_Based_Test("pubkey/kyber_encodings.vec", "PrivateRaw,PublicRaw", "Error") {}
3✔
184

185
   private:
186
      static Botan::KyberMode name_to_mode(const std::string& algo_name) {
14✔
187
         if(algo_name == "Kyber-512-r3") {
14✔
188
            return Botan::KyberMode::Kyber512;
4✔
189
         }
190
         if(algo_name == "Kyber-512-90s-r3") {
10✔
191
            return Botan::KyberMode::Kyber512_90s;
2✔
192
         }
193
         if(algo_name == "Kyber-768-r3") {
8✔
194
            return Botan::KyberMode::Kyber768;
2✔
195
         }
196
         if(algo_name == "Kyber-768-90s-r3") {
6✔
197
            return Botan::KyberMode::Kyber768_90s;
2✔
198
         }
199
         if(algo_name == "Kyber-1024-r3") {
4✔
200
            return Botan::KyberMode::Kyber1024;
2✔
201
         }
202
         if(algo_name == "Kyber-1024-90s-r3") {
2✔
203
            return Botan::KyberMode::Kyber1024_90s;
2✔
204
         }
205

206
         throw Botan::Invalid_Argument("don't know kyber mode: " + algo_name);
×
207
      }
208

209
   public:
210
      bool skip_this_test(const std::string& algo_name, const VarMap& /*vars*/) override {
7✔
211
         const auto mode = name_to_mode(algo_name);
7✔
212
   #if defined(BOTAN_HAS_KYBER)
213
         if(!mode.is_90s()) {
7✔
214
            return false;
215
         }
216
   #endif
217
   #if defined(BOTAN_HAS_KYBER_90S)
218
         if(mode.is_90s()) {
3✔
219
            return false;
3✔
220
         }
221
   #endif
222

223
         BOTAN_UNUSED(algo_name, mode);
224
         return true;
225
      }
226

227
      Test::Result run_one_test(const std::string& algo_name, const VarMap& vars) override {
7✔
228
         Test::Result result("kyber_encodings");
7✔
229

230
         const auto mode = name_to_mode(algo_name);
7✔
231

232
         const auto pk_raw = Botan::hex_decode(vars.get_req_str("PublicRaw"));
14✔
233
         const auto sk_raw = Botan::hex_decode_locked(vars.get_req_str("PrivateRaw"));
14✔
234
         const auto error = vars.get_opt_str("Error", "");
14✔
235

236
         if(!error.empty()) {
7✔
237
            // negative tests
238

239
            result.test_throws("failing decoding", error, [&] {
4✔
240
               if(!sk_raw.empty()) {
2✔
241
                  Botan::Kyber_PrivateKey(sk_raw, mode);
1✔
242
               }
243
               if(!pk_raw.empty()) {
1✔
244
                  Botan::Kyber_PublicKey(pk_raw, mode);
1✔
245
               }
246
            });
×
247

248
            return result;
2✔
249
         } else {
250
            const auto skr = std::make_unique<Botan::Kyber_PrivateKey>(sk_raw, mode);
5✔
251
            const auto pkr = std::make_unique<Botan::Kyber_PublicKey>(pk_raw, mode);
5✔
252

253
            result.test_eq("sk's encoding of pk", skr->public_key_bits(), pk_raw);
10✔
254
            result.test_eq("sk's encoding of sk", skr->private_key_bits(), sk_raw);
10✔
255
            result.test_eq("pk's encoding of pk", skr->public_key_bits(), pk_raw);
15✔
256
         }
5✔
257

258
         return result;
5✔
259
      }
21✔
260
};
261

262
BOTAN_REGISTER_TEST("kyber", "kyber_encodings", Kyber_Encoding_Test);
263

264
class Kyber_Keygen_Tests final : public PK_Key_Generation_Test {
×
265
   public:
266
      std::vector<std::string> keygen_params() const override {
1✔
267
         return {
1✔
268
   #if defined(BOTAN_HAS_KYBER_90S)
269
            "Kyber-512-90s-r3", "Kyber-768-90s-r3", "Kyber-1024-90s-r3",
270
   #endif
271
   #if defined(BOTAN_HAS_KYBER)
272
               "Kyber-512-r3", "Kyber-768-r3", "Kyber-1024-r3",
273
   #endif
274
         };
7✔
275
      }
276

277
      std::string algo_name() const override { return "Kyber"; }
18✔
278
};
279

280
BOTAN_REGISTER_TEST("kyber", "kyber_keygen", Kyber_Keygen_Tests);
281
#endif
282

283
}  // namespace Botan_Tests
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