• 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

96.64
/src/tests/test_dilithium.cpp
1
/*
2
 * Tests for Crystals Dilithium
3
 * - KAT tests using the KAT vectors from
4
 *   https://csrc.nist.gov/CSRC/media/Projects/post-quantum-cryptography/documents/round-3/submissions/Dilithium-Round3.zip
5
 *
6
 * (C) 2022,2023 Jack Lloyd
7
 * (C) 2022 Manuel Glaser, Michael Boric, René Meusel - Rohde & Schwarz Cybersecurity
8
 *
9
 * Botan is released under the Simplified BSD License (see license.txt)
10
 */
11

12
#include "test_rng.h"
13
#include "tests.h"
14

15
#if defined(BOTAN_HAS_DILITHIUM_COMMON)
16
   #include <botan/dilithium.h>
17
   #include <botan/hash.h>
18
   #include <botan/pk_algs.h>
19
   #include <botan/pubkey.h>
20

21
   #include "test_pubkey.h"
22
#endif
23

24
namespace Botan_Tests {
25

26
#if defined(BOTAN_HAS_DILITHIUM_COMMON) && defined(BOTAN_HAS_AES)
27

28
template <typename DerivedT>
29
class Dilithium_KAT_Tests : public Text_Based_Test {
×
30
   public:
31
      Dilithium_KAT_Tests() : Text_Based_Test(DerivedT::test_vector, "Seed,Msg,HashPk,HashSk,HashSig", "Sig") {}
36✔
32

33
      Test::Result run_one_test(const std::string& name, const VarMap& vars) override {
1,200✔
34
         Test::Result result(name);
1,200✔
35

36
         // read input from test file
37
         const auto ref_seed = vars.get_req_bin("Seed");
2,400✔
38
         const auto ref_msg = vars.get_req_bin("Msg");
2,400✔
39
         const auto ref_pk_hash = vars.get_req_bin("HashPk");
2,400✔
40
         const auto ref_sk_hash = vars.get_req_bin("HashSk");
2,400✔
41
         const auto ref_sig_hash = vars.get_req_bin("HashSig");
2,400✔
42
         const auto ref_sig = vars.get_opt_bin("Sig");
2,400✔
43

44
         auto sha3_256 = Botan::HashFunction::create_or_throw("SHA-3(256)");
1,200✔
45

46
         auto dilithium_test_rng = std::make_unique<CTR_DRBG_AES256>(ref_seed);
1,200✔
47

48
         Botan::Dilithium_PrivateKey priv_key(*dilithium_test_rng, DerivedT::mode);
1,200✔
49

50
         result.test_eq(
6,000✔
51
            "generated expected private key hash", sha3_256->process(priv_key.private_key_bits()), ref_sk_hash);
1,200✔
52

53
         result.test_eq(
6,000✔
54
            "generated expected public key hash", sha3_256->process(priv_key.public_key_bits()), ref_pk_hash);
1,200✔
55

56
         auto signer = Botan::PK_Signer(priv_key, *dilithium_test_rng, DerivedT::sign_param);
1,200✔
57
         auto signature = signer.sign_message(ref_msg.data(), ref_msg.size(), *dilithium_test_rng);
2,400✔
58

59
         result.test_eq("generated expected signature hash", sha3_256->process(signature), ref_sig_hash);
4,800✔
60
         if(!ref_sig.empty()) {
1,200✔
61
            result.test_eq("generated expected signature", signature, ref_sig);
24✔
62
         }
63

64
         Botan::Dilithium_PublicKey pub_key(priv_key.public_key_bits(), DerivedT::mode);
2,400✔
65
         auto verifier = Botan::PK_Verifier(pub_key, "");
1,200✔
66
         verifier.update(ref_msg.data(), ref_msg.size());
1,200✔
67
         result.confirm("signature verifies", verifier.check_signature(signature.data(), signature.size()));
2,400✔
68

69
         // test validating incorrect wrong signagture
70
         auto mutated_signature = Test::mutate_vec(signature);
1,200✔
71
         result.confirm("invalid signature rejected",
2,400✔
72
                        !verifier.check_signature(mutated_signature.data(), mutated_signature.size()));
1,200✔
73

74
         verifier.update(ref_msg.data(), ref_msg.size());
1,200✔
75
         result.confirm("signature verifies", verifier.check_signature(signature.data(), signature.size()));
3,600✔
76

77
         return result;
1,200✔
78
      }
10,812✔
79
};
80

81
   // NOLINTNEXTLINE(*-macro-usage)
82
   #define REGISTER_DILITHIUM_KAT_TEST(m, rand)                                          \
83
      class DILITHIUM##m##rand final : public Dilithium_KAT_Tests<DILITHIUM##m##rand> {  \
84
         public:                                                                         \
85
            constexpr static auto test_vector = "pubkey/dilithium_" #m "_" #rand ".vec"; \
86
            constexpr static auto mode = Botan::DilithiumMode::Dilithium##m;             \
87
            constexpr static auto sign_param = #rand;                                    \
88
      };                                                                                 \
89
      BOTAN_REGISTER_TEST("dilithium", "dilithium_kat_" #m "_" #rand, DILITHIUM##m##rand)
90

91
   #if defined(BOTAN_HAS_DILITHIUM)
92
REGISTER_DILITHIUM_KAT_TEST(4x4, Deterministic);
1✔
93
REGISTER_DILITHIUM_KAT_TEST(6x5, Deterministic);
1✔
94
REGISTER_DILITHIUM_KAT_TEST(8x7, Deterministic);
1✔
95
REGISTER_DILITHIUM_KAT_TEST(4x4, Randomized);
1✔
96
REGISTER_DILITHIUM_KAT_TEST(6x5, Randomized);
1✔
97
REGISTER_DILITHIUM_KAT_TEST(8x7, Randomized);
1✔
98
   #endif
99

100
   #if defined(BOTAN_HAS_DILITHIUM_AES)
101
REGISTER_DILITHIUM_KAT_TEST(4x4_AES, Deterministic);
1✔
102
REGISTER_DILITHIUM_KAT_TEST(6x5_AES, Deterministic);
1✔
103
REGISTER_DILITHIUM_KAT_TEST(8x7_AES, Deterministic);
1✔
104
REGISTER_DILITHIUM_KAT_TEST(4x4_AES, Randomized);
1✔
105
REGISTER_DILITHIUM_KAT_TEST(6x5_AES, Randomized);
1✔
106
REGISTER_DILITHIUM_KAT_TEST(8x7_AES, Randomized);
1✔
107
   #endif
108

109
class DilithiumRoundtripTests final : public Test {
×
110
   public:
111
      static Test::Result run_roundtrip(const char* test_name, Botan::DilithiumMode mode, bool randomized) {
12✔
112
         Test::Result result(test_name);
12✔
113

114
         auto sign = [randomized](const auto& private_key, const auto& msg) {
48✔
115
            const std::string param = (randomized) ? "Randomized" : "Deterministic";
54✔
116
            auto signer = Botan::PK_Signer(private_key, Test::rng(), param);
36✔
117
            return signer.sign_message(msg, Test::rng());
36✔
118
         };
48✔
119

120
         auto verify = [](const auto& public_key, const auto& msg, const auto& signature) {
192✔
121
            auto verifier = Botan::PK_Verifier(public_key, "");
180✔
122
            verifier.update(msg);
180✔
123
            return verifier.check_signature(signature);
360✔
124
         };
180✔
125

126
         const std::string msg = "The quick brown fox jumps over the lazy dog.";
12✔
127
         const std::vector<uint8_t> msgvec(msg.data(), msg.data() + msg.size());
12✔
128

129
         Botan::Dilithium_PrivateKey priv_key(Test::rng(), mode);
12✔
130
         const Botan::Dilithium_PublicKey& pub_key = priv_key;
12✔
131

132
         const auto sig_before_codec = sign(priv_key, msgvec);
12✔
133

134
         const auto priv_key_encoded = priv_key.private_key_bits();
12✔
135
         const auto pub_key_encoded = priv_key.public_key_bits();
12✔
136

137
         Botan::Dilithium_PrivateKey priv_key_decoded(priv_key_encoded, mode);
12✔
138
         Botan::Dilithium_PublicKey pub_key_decoded(pub_key_encoded, mode);
12✔
139

140
         const auto sig_after_codec = sign(priv_key_decoded, msgvec);
12✔
141

142
         result.confirm("Pubkey: before,   Sig: before", verify(pub_key, msgvec, sig_before_codec));
24✔
143
         result.confirm("Pubkey: before,   Sig: after", verify(pub_key, msgvec, sig_after_codec));
24✔
144
         result.confirm("Pubkey: after,    Sig: after", verify(pub_key_decoded, msgvec, sig_after_codec));
24✔
145
         result.confirm("Pubkey: after,    Sig: before", verify(pub_key_decoded, msgvec, sig_before_codec));
24✔
146
         result.confirm("Pubkey: recalc'ed Sig: before", verify(priv_key_decoded, msgvec, sig_before_codec));
24✔
147
         result.confirm("Pubkey: recalc'ed Sig: after", verify(priv_key_decoded, msgvec, sig_after_codec));
24✔
148

149
         auto tampered_msgvec = msgvec;
12✔
150
         tampered_msgvec.front() = 'X';
12✔
151
         result.confirm("Pubkey: before,   Broken Sig: before", !verify(pub_key, tampered_msgvec, sig_before_codec));
24✔
152
         result.confirm("Pubkey: before,   Broken Sig: after", !verify(pub_key, tampered_msgvec, sig_after_codec));
24✔
153
         result.confirm("Pubkey: after,    Broken Sig: after",
12✔
154
                        !verify(pub_key_decoded, tampered_msgvec, sig_after_codec));
12✔
155
         result.confirm("Pubkey: after,    Broken Sig: before",
12✔
156
                        !verify(pub_key_decoded, tampered_msgvec, sig_before_codec));
12✔
157
         result.confirm("Pubkey: recalc'ed Sig: before", !verify(priv_key_decoded, tampered_msgvec, sig_before_codec));
24✔
158
         result.confirm("Pubkey: recalc'ed Sig: after", !verify(priv_key_decoded, tampered_msgvec, sig_after_codec));
24✔
159

160
         // decoding via generic pk_algs.h
161
         const auto generic_pubkey_decoded = Botan::load_public_key(pub_key.algorithm_identifier(), pub_key_encoded);
12✔
162
         const auto generic_privkey_decoded =
12✔
163
            Botan::load_private_key(priv_key.algorithm_identifier(), priv_key_encoded);
12✔
164

165
         result.test_not_null("generic pubkey", generic_pubkey_decoded);
12✔
166
         result.test_not_null("generic privkey", generic_privkey_decoded);
12✔
167

168
         const auto sig_after_generic_codec = sign(*generic_privkey_decoded, msgvec);
12✔
169

170
         result.confirm("verification with generic public key",
24✔
171
                        verify(*generic_pubkey_decoded, msgvec, sig_before_codec));
12✔
172
         result.confirm("verification of signature with generic private key",
24✔
173
                        verify(*generic_pubkey_decoded, msgvec, sig_after_generic_codec));
12✔
174
         result.confirm("verification with generic private key",
24✔
175
                        verify(*generic_privkey_decoded, msgvec, sig_before_codec));
12✔
176

177
         return result;
12✔
178
      }
120✔
179

180
      std::vector<Test::Result> run() override {
1✔
181
         std::vector<Test::Result> results;
1✔
182

183
   #if defined(BOTAN_HAS_DILITHIUM)
184
         results.push_back(run_roundtrip("Dilithium_4x4_Common", Botan::DilithiumMode::Dilithium4x4, false));
2✔
185
         results.push_back(run_roundtrip("Dilithium_6x5_Common", Botan::DilithiumMode::Dilithium6x5, false));
2✔
186
         results.push_back(run_roundtrip("Dilithium_8x7_Common", Botan::DilithiumMode::Dilithium8x7, false));
2✔
187
         results.push_back(run_roundtrip("Dilithium_4x4_Common_Randomized", Botan::DilithiumMode::Dilithium4x4, true));
2✔
188
         results.push_back(run_roundtrip("Dilithium_6x5_Common_Randomized", Botan::DilithiumMode::Dilithium6x5, true));
2✔
189
         results.push_back(run_roundtrip("Dilithium_8x7_Common_Randomized", Botan::DilithiumMode::Dilithium8x7, true));
2✔
190
   #endif
191

192
   #if defined(BOTAN_HAS_DILITHIUM_AES)
193
         results.push_back(run_roundtrip("Dilithium_4x4_AES", Botan::DilithiumMode::Dilithium4x4_AES, false));
2✔
194
         results.push_back(run_roundtrip("Dilithium_6x5_AES", Botan::DilithiumMode::Dilithium6x5_AES, false));
2✔
195
         results.push_back(run_roundtrip("Dilithium_8x7_AES", Botan::DilithiumMode::Dilithium8x7_AES, false));
2✔
196
         results.push_back(run_roundtrip("Dilithium_4x4_AES_Randomized", Botan::DilithiumMode::Dilithium4x4_AES, true));
2✔
197
         results.push_back(run_roundtrip("Dilithium_6x5_AES_Randomized", Botan::DilithiumMode::Dilithium6x5_AES, true));
2✔
198
         results.push_back(run_roundtrip("Dilithium_8x7_AES_Randomized", Botan::DilithiumMode::Dilithium8x7_AES, true));
2✔
199
   #endif
200

201
         return results;
1✔
202
      }
×
203
};
204

205
BOTAN_REGISTER_TEST("dilithium", "dilithium_roundtrips", DilithiumRoundtripTests);
206

207
class Dilithium_Keygen_Tests final : public PK_Key_Generation_Test {
×
208
   public:
209
      std::vector<std::string> keygen_params() const override {
1✔
210
         return {
1✔
211
   #if defined(BOTAN_HAS_DILITHIUM_AES)
212
            "Dilithium-4x4-AES-r3", "Dilithium-6x5-AES-r3", "Dilithium-8x7-AES-r3",
213
   #endif
214
   #if defined(BOTAN_HAS_DILITHIUM)
215
               "Dilithium-4x4-r3", "Dilithium-6x5-r3", "Dilithium-8x7-r3",
216
   #endif
217
         };
7✔
218
      }
219

220
      std::string algo_name() const override { return "Dilithium"; }
18✔
221
};
222

223
BOTAN_REGISTER_TEST("pubkey", "dilithium_keygen", Dilithium_Keygen_Tests);
224

225
#endif
226

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