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

randombit / botan / 5111374265

29 May 2023 11:19AM UTC coverage: 92.227% (+0.5%) from 91.723%
5111374265

push

github

randombit
Next release will be 3.1.0. Update release notes

75588 of 81959 relevant lines covered (92.23%)

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

164
      #if defined(BOTAN_HAS_KYBER_90S)
165
REGISTER_KYBER_KAT_TEST(512_90s);
103✔
166
REGISTER_KYBER_KAT_TEST(768_90s);
103✔
167
REGISTER_KYBER_KAT_TEST(1024_90s);
103✔
168
      #endif
169
      #if defined(BOTAN_HAS_KYBER)
170
REGISTER_KYBER_KAT_TEST(512);
103✔
171
REGISTER_KYBER_KAT_TEST(768);
103✔
172
REGISTER_KYBER_KAT_TEST(1024);
103✔
173
      #endif
174

175
      #undef REGISTER_KYBER_KAT_TEST
176

177
   #endif
178

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

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

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

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

219
         BOTAN_UNUSED(algo_name, mode);
220
         return true;
221
      }
222

223
      Test::Result run_one_test(const std::string& algo_name, const VarMap& vars) override {
7✔
224
         Test::Result result("kyber_encodings");
7✔
225

226
         const auto mode = name_to_mode(algo_name);
7✔
227

228
         const auto pk_raw = Botan::hex_decode(vars.get_req_str("PublicRaw"));
14✔
229
         const auto sk_raw = Botan::hex_decode_locked(vars.get_req_str("PrivateRaw"));
14✔
230
         const auto error = vars.get_opt_str("Error", "");
14✔
231

232
         if(!error.empty()) {
7✔
233
            // negative tests
234

235
            result.test_throws("failing decoding", error, [&] {
4✔
236
               if(!sk_raw.empty())
2✔
237
                  Botan::Kyber_PrivateKey(sk_raw, mode);
1✔
238
               if(!pk_raw.empty())
1✔
239
                  Botan::Kyber_PublicKey(pk_raw, mode);
1✔
240
            });
×
241

242
            return result;
2✔
243
         } else {
244
            const auto skr = std::make_unique<Botan::Kyber_PrivateKey>(sk_raw, mode);
5✔
245
            const auto pkr = std::make_unique<Botan::Kyber_PublicKey>(pk_raw, mode);
5✔
246

247
            result.test_eq("sk's encoding of pk", skr->public_key_bits(), pk_raw);
10✔
248
            result.test_eq("sk's encoding of sk", skr->private_key_bits(), sk_raw);
10✔
249
            result.test_eq("pk's encoding of pk", skr->public_key_bits(), pk_raw);
15✔
250
         }
5✔
251

252
         return result;
5✔
253
      }
21✔
254
};
255

256
BOTAN_REGISTER_TEST("kyber", "kyber_encodings", Kyber_Encoding_Test);
257

258
class Kyber_Keygen_Tests final : public PK_Key_Generation_Test {
×
259
   public:
260
      std::vector<std::string> keygen_params() const override {
1✔
261
         return {
1✔
262
   #if defined(BOTAN_HAS_KYBER_90S)
263
            "Kyber-512-90s-r3", "Kyber-768-90s-r3", "Kyber-1024-90s-r3",
264
   #endif
265
   #if defined(BOTAN_HAS_KYBER)
266
               "Kyber-512-r3", "Kyber-768-r3", "Kyber-1024-r3",
267
   #endif
268
         };
7✔
269
      }
270

271
      std::string algo_name() const override { return "Kyber"; }
18✔
272
};
273

274
BOTAN_REGISTER_TEST("kyber", "kyber_keygen", Kyber_Keygen_Tests);
275
#endif
276

277
}  // 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