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

randombit / botan / 25202427239

30 Apr 2026 02:35PM UTC coverage: 89.379% (+0.02%) from 89.359%
25202427239

push

github

web-flow
Merge pull request #5552 from falko-strenzke/falko/point-not-on-curve-test

Add test that ECDH rejects points not on the curve

107166 of 119901 relevant lines covered (89.38%)

11327707.57 hits per line

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

95.89
/src/tests/test_ecdh.cpp
1
/*
2
* (C) 2015,2016 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include "tests.h"
8

9
#if defined(BOTAN_HAS_ECDH)
10
   #include "test_pubkey.h"
11
   #include <botan/ec_group.h>
12
   #include <botan/ecdh.h>
13
   #include <botan/pubkey.h>
14
#endif
15

16
namespace Botan_Tests {
17

18
namespace {
19

20
#if defined(BOTAN_HAS_ECDH)
21

22
class ECDH_KAT_Tests final : public PK_Key_Agreement_Test {
23
   public:
24
      ECDH_KAT_Tests() : PK_Key_Agreement_Test("ECDH", "pubkey/ecdh.vec", "Secret,CounterKey,K", "KDF") {}
2✔
25

26
      std::string default_kdf(const VarMap& /*unused*/) const override { return "Raw"; }
156✔
27

28
      bool skip_this_test(const std::string& group_id, const VarMap& /*vars*/) override {
156✔
29
         return !Botan::EC_Group::supports_named_group(group_id);
156✔
30
      }
31

32
      std::unique_ptr<Botan::Private_Key> load_our_key(const std::string& group_id, const VarMap& vars) override {
156✔
33
         const auto group = Botan::EC_Group::from_name(group_id);
156✔
34
         const Botan::BigInt secret = vars.get_req_bn("Secret");
156✔
35
         return std::make_unique<Botan::ECDH_PrivateKey>(this->rng(), group, secret);
468✔
36
      }
156✔
37

38
      std::vector<uint8_t> load_their_key(const std::string& /*header*/, const VarMap& vars) override {
156✔
39
         return vars.get_req_bin("CounterKey");
156✔
40
      }
41
};
42

43
class ECDH_Keygen_Tests final : public PK_Key_Generation_Test {
1✔
44
   public:
45
      std::vector<std::string> keygen_params() const override {
1✔
46
         return {
1✔
47
            "secp256r1", "secp384r1", "secp521r1", "brainpool256r1", "brainpool384r1", "brainpool512r1", "frp256v1"};
1✔
48
      }
49

50
      std::string algo_name() const override { return "ECDH"; }
7✔
51

52
      std::unique_ptr<Botan::Public_Key> public_key_from_raw(std::string_view keygen_params,
7✔
53
                                                             std::string_view /* provider */,
54
                                                             std::span<const uint8_t> raw_pk) const override {
55
         const auto group = Botan::EC_Group(keygen_params);
7✔
56
         const auto public_key = Botan::EC_AffinePoint(group, raw_pk);
7✔
57
         return std::make_unique<Botan::ECDH_PublicKey>(group, public_key);
21✔
58
      }
7✔
59
};
60

61
class ECDH_AllGroups_Tests : public Test {
1✔
62
   public:
63
      std::vector<Test::Result> run() override {
1✔
64
         std::vector<Test::Result> results;
1✔
65

66
         for(const std::string& group_name : Botan::EC_Group::known_named_groups()) {
29✔
67
            Test::Result result("ECDH " + group_name);
28✔
68

69
            result.start_timer();
28✔
70

71
            const std::string kdf = "Raw";
28✔
72

73
            try {
28✔
74
               const auto group = Botan::EC_Group::from_name(group_name);
28✔
75

76
               // Regression test: prohibit loading an all-zero private key
77
               result.test_throws<Botan::Invalid_Argument>("all-zero private key is unacceptable", [&] {
28✔
78
                  const auto one = Botan::EC_Scalar::one(group);
28✔
79
                  const auto zero = one - one;  // NOLINT(*-redundant-expression)
28✔
80
                  Botan::ECDH_PrivateKey(group, zero);
28✔
81
               });
56✔
82

83
               // Regression test: prohibit loading a public point that is the identity (point at infinity)
84
               result.test_throws<Botan::Invalid_Argument>("point at infinity isn't a valid public key", [&] {
28✔
85
                  const auto infinity = Botan::EC_AffinePoint::identity(group);
28✔
86
                  Botan::ECDH_PublicKey(group, infinity);
28✔
87
               });
28✔
88

89
               // Regression test: prohibit ECDH-agreement with all-zero public value
90
               result.test_throws<Botan::Decoding_Error>("ECDH public value is point-at-infinity", [&] {
28✔
91
                  const auto sk = Botan::ECDH_PrivateKey(rng(), group);
28✔
92
                  const Botan::PK_Key_Agreement ka(sk, rng(), kdf);
28✔
93
                  std::vector<uint8_t> sec1_infinity(1, 0x00);
28✔
94
                  const auto a_ss = ka.derive_key(0, sec1_infinity);
28✔
95
               });
56✔
96

97
               // Regression test: prohibit loading a point not on the curve
98
               result.test_throws<Botan::Decoding_Error>("point is not on curve", [&] {
28✔
99
                  const auto& base_point = Botan::EC_AffinePoint::generator(group);
28✔
100
                  auto encoded = base_point.serialize_uncompressed();
28✔
101
                  encoded[3] -= 1;
28✔
102

103
                  const Botan::ECDH_PrivateKey a_priv(rng(), group);
28✔
104
                  const auto a_pub = a_priv.public_value();
28✔
105
                  const Botan::PK_Key_Agreement a_ka(a_priv, rng(), kdf);
56✔
106
                  const auto a_ss = a_ka.derive_key(0, encoded);
28✔
107
               });
84✔
108

109
               for(size_t i = 0; i != 100; ++i) {
2,828✔
110
                  const Botan::ECDH_PrivateKey a_priv(rng(), group);
2,800✔
111
                  const auto a_pub = a_priv.public_value();
2,800✔
112

113
                  const Botan::ECDH_PrivateKey b_priv(rng(), group);
2,800✔
114
                  const auto b_pub = b_priv.public_value();
2,800✔
115

116
                  const Botan::PK_Key_Agreement a_ka(a_priv, rng(), kdf);
2,800✔
117
                  const auto a_ss = a_ka.derive_key(0, b_pub);
2,800✔
118

119
                  const Botan::PK_Key_Agreement b_ka(b_priv, rng(), kdf);
2,800✔
120
                  const auto b_ss = b_ka.derive_key(0, a_pub);
2,800✔
121

122
                  result.test_bin_eq("Same shared secret", a_ss.bits_of(), b_ss.bits_of());
8,400✔
123
               }
11,200✔
124
            } catch(std::exception& e) {
28✔
125
               result.test_failure("Exception", e.what());
×
126
            }
×
127

128
            result.end_timer();
28✔
129

130
            results.push_back(result);
28✔
131
         }
28✔
132

133
         return results;
1✔
134
      }
×
135
};
136

137
BOTAN_REGISTER_TEST("pubkey", "ecdh_kat", ECDH_KAT_Tests);
138
BOTAN_REGISTER_TEST("pubkey", "ecdh_keygen", ECDH_Keygen_Tests);
139
BOTAN_REGISTER_TEST("pubkey", "ecdh_all_groups", ECDH_AllGroups_Tests);
140

141
#endif
142

143
}  // namespace
144

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

© 2026 Coveralls, Inc