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

randombit / botan / 24063525848

06 Apr 2026 10:36PM UTC coverage: 89.448% (-0.007%) from 89.455%
24063525848

push

github

web-flow
Merge pull request #5521 from randombit/jack/fix-rollup

Rollup of small fixes

105878 of 118368 relevant lines covered (89.45%)

11475460.89 hits per line

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

82.73
/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
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
21
   #include <botan/ec_point.h>
22
#endif
23

24
namespace Botan {
25

26
size_t EC_PublicKey::key_length() const {
1,989✔
27
   return domain().get_p_bits();
1,989✔
28
}
29

30
size_t EC_PublicKey::estimated_strength() const {
1,505✔
31
   return ecp_work_factor(key_length());
1,505✔
32
}
33

34
namespace {
35

36
EC_Group_Encoding default_encoding_for(const EC_Group& group) {
26,166✔
37
   if(group.get_curve_oid().empty()) {
26,166✔
38
      return EC_Group_Encoding::Explicit;
39
   } else {
40
      return EC_Group_Encoding::NamedCurve;
26,152✔
41
   }
42
}
43

44
}  // namespace
45

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

54
EC_PublicKey::EC_PublicKey(const EC_Group& group, const EC_AffinePoint& pub_point) {
12,786✔
55
   m_public_key = std::make_shared<const EC_PublicKey_Data>(group, pub_point);
12,786✔
56
   m_domain_encoding = default_encoding_for(domain());  // NOLINT(*-prefer-member-initializer)
12,758✔
57
}
12,786✔
58

59
EC_PublicKey::EC_PublicKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) {
4,800✔
60
   m_public_key = std::make_shared<const EC_PublicKey_Data>(EC_Group(alg_id.parameters()), key_bits);
9,572✔
61
   m_domain_encoding = default_encoding_for(domain());  // NOLINT(*-prefer-member-initializer)
4,763✔
62
}
4,800✔
63

64
const EC_Group& EC_PublicKey::domain() const {
71,191✔
65
   BOTAN_STATE_CHECK(m_public_key != nullptr);
71,191✔
66
   return m_public_key->group();
71,191✔
67
}
68

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

76
const EC_AffinePoint& EC_PublicKey::_public_ec_point() const {
21,012✔
77
   BOTAN_STATE_CHECK(m_public_key != nullptr);
21,012✔
78
   return m_public_key->public_key();
21,012✔
79
}
80

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

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

90
std::vector<uint8_t> EC_PublicKey::raw_public_key_bits() const {
2,402✔
91
   return _public_ec_point().serialize(point_encoding());
2,402✔
92
}
93

94
std::vector<uint8_t> EC_PublicKey::public_key_bits() const {
2,146✔
95
   return raw_public_key_bits();
2,146✔
96
}
97

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

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

107
   m_point_encoding = enc;
106✔
108
}
106✔
109

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

115
   m_domain_encoding = form;
×
116
}
×
117

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

123
const EC_Scalar& EC_PrivateKey::_private_key() const {
10,844✔
124
   BOTAN_STATE_CHECK(m_private_key != nullptr);
10,844✔
125
   return m_private_key->private_key();
10,844✔
126
}
127

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

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

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

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

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

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

176
EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id,
1,913✔
177
                             std::span<const uint8_t> key_bits,
178
                             bool with_modular_inverse) :
×
179
      m_with_modular_inverse(with_modular_inverse) {
1,913✔
180
   const EC_Group group(alg_id.parameters());
1,913✔
181

182
   OID key_parameters;
1,671✔
183
   secure_vector<uint8_t> private_key_bits;
1,671✔
184
   secure_vector<uint8_t> public_key_bits;
1,671✔
185

186
   BER_Decoder(key_bits, BER_Decoder::Limits::DER())
3,342✔
187
      .start_sequence()
1,671✔
188
      .decode_and_check<size_t>(1, "Unknown version code for ECC key")
1,671✔
189
      .decode(private_key_bits, ASN1_Type::OctetString)
1,671✔
190
      .decode_optional(key_parameters, ASN1_Type(0), ASN1_Class::ExplicitContextSpecific)
3,342✔
191
      .decode_optional_string(public_key_bits, ASN1_Type::BitString, 1, ASN1_Class::ExplicitContextSpecific)
1,667✔
192
      .end_cons()
1,667✔
193
      .verify_end();
1,667✔
194

195
   m_private_key = std::make_shared<EC_PrivateKey_Data>(group, private_key_bits);
1,667✔
196

197
   if(public_key_bits.empty()) {
1,653✔
198
      m_public_key = m_private_key->public_key(with_modular_inverse);
11✔
199
   } else {
200
      m_public_key = std::make_shared<EC_PublicKey_Data>(group, public_key_bits);
1,660✔
201
   }
202

203
   m_domain_encoding = default_encoding_for(domain());
3,260✔
204
}
3,666✔
205

206
bool EC_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const {
103✔
207
   if(!m_private_key) {
103✔
208
      return false;
209
   }
210

211
   if(!EC_PublicKey::check_key(rng, strong)) {
103✔
212
      return false;
213
   }
214

215
   // Verify that the public key is consistent with the private key.
216
   // For ECKCDSA/ECGDSA the derivation is g^(x^-1), for all others it is g^x.
217
   auto expected = m_private_key->public_key(m_with_modular_inverse);
103✔
218
   return expected->public_key() == _public_ec_point();
103✔
219
}
103✔
220

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

243
const BigInt& EC_PrivateKey::get_int_field(std::string_view field) const {
10✔
244
   if(field == "x") {
10✔
245
      return this->private_value();
9✔
246
   } else {
247
      return EC_PublicKey::get_int_field(field);
1✔
248
   }
249
}
250

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