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

randombit / botan / 23151525988

16 Mar 2026 03:26PM UTC coverage: 89.774% (+0.02%) from 89.759%
23151525988

Pull #5451

github

web-flow
Merge c5a4f30ee into 4f6f5bbaf
Pull Request #5451: MLDSA-composite

105271 of 117262 relevant lines covered (89.77%)

12140285.62 hits per line

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

83.69
/src/lib/pubkey/ecc_key/ecc_key.cpp
1
/*
2
* ECC Key implementation
3
* (C) 2007 Manuel Hartl, FlexSecure GmbH
4
*          Falko Strenzke, FlexSecure GmbH
5
*     2008-2010 Jack Lloyd
6
*
7
* Botan is released under the Simplified BSD License (see license.txt)
8
*/
9

10
#include <botan/ecc_key.h>
11

12
#include <botan/assert.h>
13
#include <botan/ber_dec.h>
14
#include <botan/der_enc.h>
15
#include <botan/secmem.h>
16
#include <botan/internal/ec_key_data.h>
17
#include <botan/internal/fmt.h>
18
#include <botan/internal/workfactor.h>
19

20
#include <memory>
21

22
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
23
   #include <botan/ec_point.h>
24
#endif
25

26
namespace Botan {
27

28
size_t EC_PublicKey::key_length() const {
1,283✔
29
   return domain().get_p_bits();
1,283✔
30
}
31

32
size_t EC_PublicKey::estimated_strength() const {
803✔
33
   return ecp_work_factor(key_length());
803✔
34
}
35

36
namespace {
37

38
EC_Group_Encoding default_encoding_for(const EC_Group& group) {
30,456✔
39
   if(group.get_curve_oid().empty()) {
30,456✔
40
      return EC_Group_Encoding::Explicit;
41
   } else {
42
      return EC_Group_Encoding::NamedCurve;
30,442✔
43
   }
44
}
45

46
}  // namespace
47

48
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
49
EC_PublicKey::EC_PublicKey(const EC_Group& group, const EC_Point& pub_point) {
×
50
   auto pt = EC_AffinePoint(group, pub_point);
×
51
   m_public_key = std::make_shared<const EC_PublicKey_Data>(group, std::move(pt));
×
52
   m_domain_encoding = default_encoding_for(domain());  // NOLINT(*-prefer-member-initializer)
×
53
}
×
54
#endif
55

56
EC_PublicKey::EC_PublicKey(const EC_Group& group, const EC_AffinePoint& pub_point) {
13,875✔
57
   m_public_key = std::make_shared<const EC_PublicKey_Data>(group, pub_point);
13,875✔
58
   m_domain_encoding = default_encoding_for(domain());  // NOLINT(*-prefer-member-initializer)
13,847✔
59
}
13,875✔
60

61
EC_PublicKey::EC_PublicKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) {
6,926✔
62
   m_public_key = std::make_shared<const EC_PublicKey_Data>(EC_Group(alg_id.parameters()), key_bits);
13,797✔
63
   m_domain_encoding = default_encoding_for(domain());  // NOLINT(*-prefer-member-initializer)
6,596✔
64
}
6,926✔
65

66
const EC_Group& EC_PublicKey::domain() const {
82,436✔
67
   BOTAN_STATE_CHECK(m_public_key != nullptr);
82,436✔
68
   return m_public_key->group();
82,436✔
69
}
70

71
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
72
const EC_Point& EC_PublicKey::public_point() const {
×
73
   BOTAN_STATE_CHECK(m_public_key != nullptr);
×
74
   return m_public_key->legacy_point();
×
75
}
76
#endif
77

78
const EC_AffinePoint& EC_PublicKey::_public_ec_point() const {
24,898✔
79
   BOTAN_STATE_CHECK(m_public_key != nullptr);
24,898✔
80
   return m_public_key->public_key();
24,898✔
81
}
82

83
bool EC_PublicKey::check_key(RandomNumberGenerator& rng, bool /*strong*/) const {
162✔
84
   // We already checked when deserializing that the point was on the curve
85
   return domain().verify_group(rng) && !_public_ec_point().is_identity();
162✔
86
}
87

88
AlgorithmIdentifier EC_PublicKey::algorithm_identifier() const {
2,675✔
89
   return AlgorithmIdentifier(object_identifier(), DER_domain());
5,350✔
90
}
91

92
std::vector<uint8_t> EC_PublicKey::raw_public_key_bits() const {
3,461✔
93
   return _public_ec_point().serialize(point_encoding());
3,461✔
94
}
95

96
std::vector<uint8_t> EC_PublicKey::public_key_bits() const {
3,205✔
97
   return raw_public_key_bits();
3,205✔
98
}
99

100
std::vector<uint8_t> EC_PublicKey::DER_domain() const {
2,683✔
101
   return domain().DER_encode(domain_format());
2,683✔
102
}
103

104
void EC_PublicKey::set_point_encoding(EC_Point_Format enc) {
106✔
105
   if(enc != EC_Point_Format::Compressed && enc != EC_Point_Format::Uncompressed && enc != EC_Point_Format::Hybrid) {
106✔
106
      throw Invalid_Argument("Invalid point encoding for EC_PublicKey");
×
107
   }
108

109
   m_point_encoding = enc;
106✔
110
}
106✔
111

112
void EC_PublicKey::set_parameter_encoding(EC_Group_Encoding form) {
×
113
   if(form == EC_Group_Encoding::NamedCurve && domain().get_curve_oid().empty()) {
×
114
      throw Invalid_Argument("Cannot used NamedCurve encoding for a curve without an OID");
×
115
   }
116

117
   m_domain_encoding = form;
×
118
}
×
119

120
const BigInt& EC_PrivateKey::private_value() const {
27✔
121
   BOTAN_STATE_CHECK(m_private_key != nullptr);
27✔
122
   return m_private_key->legacy_bigint();
27✔
123
}
124

125
const EC_Scalar& EC_PrivateKey::_private_key() const {
12,981✔
126
   BOTAN_STATE_CHECK(m_private_key != nullptr);
12,981✔
127
   return m_private_key->private_key();
12,981✔
128
}
129

130
/**
131
* EC_PrivateKey constructor
132
*/
133
EC_PrivateKey::EC_PrivateKey(RandomNumberGenerator& rng,
592✔
134
                             const EC_Group& ec_group,
135
                             const BigInt& x,
136
                             bool with_modular_inverse) {
592✔
137
   auto scalar = (x.is_zero()) ? EC_Scalar::random(ec_group, rng) : EC_Scalar::from_bigint(ec_group, x);
1,184✔
138
   m_private_key = std::make_shared<EC_PrivateKey_Data>(ec_group, std::move(scalar));
592✔
139
   m_public_key = m_private_key->public_key(rng, with_modular_inverse);
592✔
140
   m_domain_encoding = default_encoding_for(domain());
592✔
141
}
592✔
142

143
EC_PrivateKey::EC_PrivateKey(RandomNumberGenerator& rng, const EC_Group& ec_group, bool with_modular_inverse) {
6,416✔
144
   auto scalar = EC_Scalar::random(ec_group, rng);
6,416✔
145
   m_private_key = std::make_shared<EC_PrivateKey_Data>(ec_group, std::move(scalar));
6,416✔
146
   m_public_key = m_private_key->public_key(rng, with_modular_inverse);
6,416✔
147
   m_domain_encoding = default_encoding_for(domain());
6,416✔
148
}
6,416✔
149

150
EC_PrivateKey::EC_PrivateKey(const EC_Group& ec_group, const EC_Scalar& x, bool with_modular_inverse) {
47✔
151
   m_private_key = std::make_shared<EC_PrivateKey_Data>(ec_group, x);
47✔
152
   m_public_key = m_private_key->public_key(with_modular_inverse);
19✔
153
   m_domain_encoding = default_encoding_for(domain());
19✔
154
}
47✔
155

156
secure_vector<uint8_t> EC_PrivateKey::raw_private_key_bits() const {
1,834✔
157
   BOTAN_STATE_CHECK(m_private_key != nullptr);
1,834✔
158
   return m_private_key->serialize<secure_vector<uint8_t>>();
1,834✔
159
}
160

161
secure_vector<uint8_t> EC_PrivateKey::private_key_bits() const {
772✔
162
   BOTAN_STATE_CHECK(m_private_key != nullptr && m_public_key != nullptr);
772✔
163

164
   return DER_Encoder()
772✔
165
      .start_sequence()
772✔
166
      .encode(static_cast<size_t>(1))
772✔
167
      .encode(raw_private_key_bits(), ASN1_Type::OctetString)
2,316✔
168
      .start_explicit_context_specific(1)
772✔
169
      .encode(m_public_key->public_key().serialize_uncompressed(), ASN1_Type::BitString)
1,544✔
170
      .end_cons()
772✔
171
      .end_cons()
772✔
172
      .get_contents();
1,544✔
173
}
174

175
EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id,
3,622✔
176
                             std::span<const uint8_t> key_bits,
177
                             bool with_modular_inverse) {
3,622✔
178
   OID key_parameters;
3,622✔
179
   secure_vector<uint8_t> private_key_bits;
3,622✔
180
   secure_vector<uint8_t> public_key_bits;
3,622✔
181

182
   BER_Decoder(key_bits)
7,106✔
183
      .start_sequence()
4,120✔
184
      .decode_and_check<size_t>(1, "Unknown version code for ECC key")
3,484✔
185
      .decode(private_key_bits, ASN1_Type::OctetString)
3,469✔
186
      .decode_optional(key_parameters, ASN1_Type(0), ASN1_Class::ExplicitContextSpecific)
6,962✔
187
      .decode_optional_string(public_key_bits, ASN1_Type::BitString, 1, ASN1_Class::ExplicitContextSpecific)
3,458✔
188
      .end_cons();
3,452✔
189

190
   std::unique_ptr<EC_Group> group;
3,449✔
191

192
   if(!alg_id.parameters_are_empty()) {
3,449✔
193
      group = std::make_unique<EC_Group>(alg_id.parameters());
4,550✔
194
   }
195
   if(!key_parameters.empty()) {
3,243✔
196
      if(group) {
1,078✔
197
         if(EC_Group(key_parameters) != *group) {
11✔
198
            throw Invalid_Argument(
1✔
199
               "Domain parameters supplied AlgorithmIdentifier does not match the ECC private key's domain parameters in EC_PrivateKey construction");
1✔
200
         }
201
      } else {
202
         group = std::make_unique<EC_Group>(key_parameters);
2,142✔
203
      }
204
   }
205
   if(!group) {
3,239✔
206
      throw Invalid_Argument("Domain parameters are not supplied in EC_PrivateKey construction");
×
207
   }
208

209
   m_private_key = std::make_shared<EC_PrivateKey_Data>(*group, private_key_bits);
3,239✔
210

211
   if(public_key_bits.empty()) {
3,176✔
212
      m_public_key = m_private_key->public_key(with_modular_inverse);
1,368✔
213
   } else {
214
      m_public_key = std::make_shared<EC_PublicKey_Data>(*group, public_key_bits);
1,808✔
215
   }
216

217
   m_domain_encoding = default_encoding_for(domain());
2,986✔
218
}
9,961✔
219

220
bool EC_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const {
103✔
221
   if(!m_private_key) {
103✔
222
      return false;
223
   }
224

225
   return EC_PublicKey::check_key(rng, strong);
103✔
226
}
227

228
const BigInt& EC_PublicKey::get_int_field(std::string_view field) const {
2✔
229
   if(field == "public_x" || field == "public_y") {
2✔
230
      throw Not_Implemented(fmt("EC_PublicKey::get_int_field no longer implements getter for {}", field));
×
231
   } else if(field == "base_x") {
2✔
232
      return this->domain().get_g_x();
×
233
   } else if(field == "base_y") {
2✔
234
      return this->domain().get_g_y();
×
235
   } else if(field == "p") {
2✔
236
      return this->domain().get_p();
×
237
   } else if(field == "a") {
2✔
238
      return this->domain().get_a();
×
239
   } else if(field == "b") {
2✔
240
      return this->domain().get_b();
×
241
   } else if(field == "cofactor") {
2✔
242
      return this->domain().get_cofactor();
×
243
   } else if(field == "order") {
2✔
244
      return this->domain().get_order();
×
245
   } else {
246
      return Public_Key::get_int_field(field);
2✔
247
   }
248
}
249

250
const BigInt& EC_PrivateKey::get_int_field(std::string_view field) const {
10✔
251
   if(field == "x") {
10✔
252
      return this->private_value();
9✔
253
   } else {
254
      return EC_PublicKey::get_int_field(field);
1✔
255
   }
256
}
257

258
}  // namespace Botan
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