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

randombit / botan / 13102827281

02 Feb 2025 05:43PM UTC coverage: 91.225% (-0.01%) from 91.236%
13102827281

push

github

web-flow
Merge pull request #4626 from randombit/jack/fix-pt-eq

Fix EC_AffinePoint equality check

94171 of 103229 relevant lines covered (91.23%)

11590988.89 hits per line

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

93.75
/src/lib/pubkey/ec_group/ec_apoint.cpp
1
/*
2
* (C) 2024 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include <botan/ec_apoint.h>
8

9
#include <botan/ec_group.h>
10
#include <botan/ec_scalar.h>
11
#include <botan/internal/ec_inner_data.h>
12

13
namespace Botan {
14

15
EC_AffinePoint::EC_AffinePoint(std::unique_ptr<EC_AffinePoint_Data> point) : m_point(std::move(point)) {
82,629✔
16
   BOTAN_ASSERT_NONNULL(m_point);
82,629✔
17
}
82,629✔
18

19
EC_AffinePoint::EC_AffinePoint(const EC_AffinePoint& other) : m_point(other.inner().clone()) {}
12,902✔
20

21
EC_AffinePoint::EC_AffinePoint(EC_AffinePoint&& other) noexcept : m_point(std::move(other.m_point)) {}
89,910✔
22

23
EC_AffinePoint& EC_AffinePoint::operator=(const EC_AffinePoint& other) {
×
24
   if(this != &other) {
×
25
      m_point = other.inner().clone();
×
26
   }
27
   return (*this);
×
28
}
29

30
EC_AffinePoint& EC_AffinePoint::operator=(EC_AffinePoint&& other) noexcept {
1,641✔
31
   m_point.swap(other.m_point);
1,641✔
32
   return (*this);
1,641✔
33
}
34

35
EC_AffinePoint::EC_AffinePoint(const EC_Group& group, std::span<const uint8_t> bytes) {
14,350✔
36
   m_point = group._data()->point_deserialize(bytes);
14,350✔
37
   if(!m_point) {
14,350✔
38
      throw Decoding_Error("Failed to deserialize elliptic curve point");
6,254✔
39
   }
40
}
14,350✔
41

42
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
43

44
EC_Point EC_AffinePoint::to_legacy_point() const {
27,397✔
45
   return m_point->to_legacy_point();
27,397✔
46
}
47

48
EC_AffinePoint::EC_AffinePoint(const EC_Group& group, const EC_Point& pt) :
862✔
49
      EC_AffinePoint(group, pt.encode(EC_Point_Format::Uncompressed)) {}
1,724✔
50

51
#endif
52

53
bool EC_AffinePoint::operator==(const EC_AffinePoint& other) const {
1,052✔
54
   if(this == &other) {
1,052✔
55
      return true;
56
   }
57

58
   // We are relying on EC_Group to ensure there is just a single shared_ptr
59
   // for any set of group params
60
   if(this->_group() != other._group()) {
1,052✔
61
      return false;
62
   }
63

64
   auto a_is_id = this->is_identity();
1,052✔
65
   auto b_is_id = other.is_identity();
1,052✔
66

67
   if(a_is_id || b_is_id) {
1,052✔
68
      return (a_is_id == b_is_id);
×
69
   }
70

71
   auto a_xy = this->serialize_uncompressed();
1,052✔
72
   auto b_xy = other.serialize_uncompressed();
1,052✔
73
   BOTAN_ASSERT_NOMSG(a_xy.size() == b_xy.size());
1,052✔
74

75
   return CT::is_equal(a_xy.data(), b_xy.data(), a_xy.size()).as_bool();
2,104✔
76
}
2,104✔
77

78
EC_AffinePoint EC_AffinePoint::identity(const EC_Group& group) {
112✔
79
   const uint8_t id_encoding[1] = {0};
112✔
80
   return EC_AffinePoint(group, id_encoding);
112✔
81
}
82

83
EC_AffinePoint EC_AffinePoint::generator(const EC_Group& group) {
921✔
84
   // TODO it would be nice to improve this (pcurves supports returning generator directly)
85
   try {
921✔
86
      return EC_AffinePoint::from_bigint_xy(group, group.get_g_x(), group.get_g_y()).value();
2,763✔
87
   } catch(...) {
×
88
      throw Internal_Error("EC_AffinePoint::generator curve rejected generator");
×
89
   }
×
90
}
91

92
std::optional<EC_AffinePoint> EC_AffinePoint::from_bigint_xy(const EC_Group& group, const BigInt& x, const BigInt& y) {
13,124✔
93
   if(x.is_negative() || x >= group.get_p()) {
13,124✔
94
      return {};
21✔
95
   }
96
   if(y.is_negative() || y >= group.get_p()) {
13,103✔
97
      return {};
18✔
98
   }
99

100
   const size_t fe_bytes = group.get_p_bytes();
13,085✔
101
   std::vector<uint8_t> sec1(1 + 2 * fe_bytes);
13,085✔
102
   sec1[0] = 0x04;
13,085✔
103
   x.serialize_to(std::span{sec1}.subspan(1, fe_bytes));
13,085✔
104
   y.serialize_to(std::span{sec1}.last(fe_bytes));
13,085✔
105

106
   return EC_AffinePoint::deserialize(group, sec1);
13,085✔
107
}
39,255✔
108

109
size_t EC_AffinePoint::field_element_bytes() const {
43,166✔
110
   return inner().field_element_bytes();
43,166✔
111
}
112

113
bool EC_AffinePoint::is_identity() const {
45,743✔
114
   return inner().is_identity();
45,743✔
115
}
116

117
EC_AffinePoint EC_AffinePoint::hash_to_curve_ro(const EC_Group& group,
24✔
118
                                                std::string_view hash_fn,
119
                                                std::span<const uint8_t> input,
120
                                                std::span<const uint8_t> domain_sep) {
121
   auto pt = group._data()->point_hash_to_curve_ro(hash_fn, input, domain_sep);
24✔
122
   return EC_AffinePoint(std::move(pt));
48✔
123
}
24✔
124

125
EC_AffinePoint EC_AffinePoint::hash_to_curve_nu(const EC_Group& group,
33✔
126
                                                std::string_view hash_fn,
127
                                                std::span<const uint8_t> input,
128
                                                std::span<const uint8_t> domain_sep) {
129
   auto pt = group._data()->point_hash_to_curve_nu(hash_fn, input, domain_sep);
33✔
130
   return EC_AffinePoint(std::move(pt));
60✔
131
}
30✔
132

133
EC_AffinePoint::~EC_AffinePoint() = default;
193,537✔
134

135
std::optional<EC_AffinePoint> EC_AffinePoint::deserialize(const EC_Group& group, std::span<const uint8_t> bytes) {
30,060✔
136
   if(auto pt = group._data()->point_deserialize(bytes)) {
30,060✔
137
      return EC_AffinePoint(std::move(pt));
59,882✔
138
   } else {
139
      return {};
119✔
140
   }
30,060✔
141
}
142

143
EC_AffinePoint EC_AffinePoint::g_mul(const EC_Scalar& scalar, RandomNumberGenerator& rng, std::vector<BigInt>& ws) {
15,362✔
144
   auto pt = scalar._inner().group()->point_g_mul(scalar.inner(), rng, ws);
15,362✔
145
   return EC_AffinePoint(std::move(pt));
30,724✔
146
}
15,362✔
147

148
EC_AffinePoint EC_AffinePoint::mul(const EC_Scalar& scalar, RandomNumberGenerator& rng, std::vector<BigInt>& ws) const {
14,610✔
149
   return EC_AffinePoint(inner().mul(scalar._inner(), rng, ws));
29,220✔
150
}
151

152
secure_vector<uint8_t> EC_AffinePoint::mul_x_only(const EC_Scalar& scalar,
5,881✔
153
                                                  RandomNumberGenerator& rng,
154
                                                  std::vector<BigInt>& ws) const {
155
   return inner().mul_x_only(scalar._inner(), rng, ws);
5,881✔
156
}
157

158
std::optional<EC_AffinePoint> EC_AffinePoint::mul_px_qy(const EC_AffinePoint& p,
3,472✔
159
                                                        const EC_Scalar& x,
160
                                                        const EC_AffinePoint& q,
161
                                                        const EC_Scalar& y,
162
                                                        RandomNumberGenerator& rng) {
163
   auto pt = p._inner().group()->mul_px_qy(p._inner(), x._inner(), q._inner(), y._inner(), rng);
3,472✔
164
   if(pt) {
3,472✔
165
      return EC_AffinePoint(std::move(pt));
6,552✔
166
   } else {
167
      return {};
196✔
168
   }
169
}
3,472✔
170

171
EC_AffinePoint EC_AffinePoint::add(const EC_AffinePoint& q) const {
7,753✔
172
   auto pt = _inner().group()->affine_add(_inner(), q._inner());
7,753✔
173
   return EC_AffinePoint(std::move(pt));
15,504✔
174
}
7,752✔
175

176
EC_AffinePoint EC_AffinePoint::negate() const {
9,512✔
177
   auto pt = this->_inner().group()->affine_neg(this->_inner());
9,512✔
178
   return EC_AffinePoint(std::move(pt));
19,024✔
179
}
9,512✔
180

181
std::vector<uint8_t> EC_AffinePoint::serialize(EC_Point_Format format) const {
6,960✔
182
   if(format == EC_Point_Format::Compressed) {
6,960✔
183
      return this->serialize_compressed();
118✔
184
   } else if(format == EC_Point_Format::Uncompressed) {
6,842✔
185
      return this->serialize_uncompressed();
6,750✔
186
   } else {
187
      // The deprecated "hybrid" point encoding
188
      // TODO(Botan4) Remove this
189
      auto enc = this->serialize_uncompressed();
92✔
190
      const bool y_is_odd = (enc[enc.size() - 1] & 0x01) == 0x01;
92✔
191
      enc.front() = y_is_odd ? 0x07 : 0x06;
171✔
192
      return enc;
92✔
193
   }
92✔
194
}
195

196
void EC_AffinePoint::serialize_x_to(std::span<uint8_t> bytes) const {
610✔
197
   BOTAN_STATE_CHECK(!this->is_identity());
610✔
198
   m_point->serialize_x_to(bytes);
610✔
199
}
610✔
200

201
void EC_AffinePoint::serialize_y_to(std::span<uint8_t> bytes) const {
74✔
202
   BOTAN_STATE_CHECK(!this->is_identity());
74✔
203
   m_point->serialize_y_to(bytes);
74✔
204
}
74✔
205

206
void EC_AffinePoint::serialize_xy_to(std::span<uint8_t> bytes) const {
234✔
207
   BOTAN_STATE_CHECK(!this->is_identity());
234✔
208
   m_point->serialize_xy_to(bytes);
234✔
209
}
234✔
210

211
void EC_AffinePoint::serialize_compressed_to(std::span<uint8_t> bytes) const {
11,984✔
212
   BOTAN_STATE_CHECK(!this->is_identity());
11,984✔
213
   m_point->serialize_compressed_to(bytes);
11,984✔
214
}
11,984✔
215

216
void EC_AffinePoint::serialize_uncompressed_to(std::span<uint8_t> bytes) const {
30,278✔
217
   BOTAN_STATE_CHECK(!this->is_identity());
30,278✔
218
   m_point->serialize_uncompressed_to(bytes);
30,278✔
219
}
30,278✔
220

221
EC_AffinePoint EC_AffinePoint::_from_inner(std::unique_ptr<EC_AffinePoint_Data> inner) {
2,122✔
222
   return EC_AffinePoint(std::move(inner));
4,244✔
223
}
224

225
const std::shared_ptr<const EC_Group_Data>& EC_AffinePoint::_group() const {
15,356✔
226
   return inner().group();
15,356✔
227
}
228

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