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

randombit / botan / 26995937053

04 Jun 2026 09:38PM UTC coverage: 89.394% (-2.3%) from 91.672%
26995937053

push

github

web-flow
Merge pull request #5642 from randombit/jack/prefetch-in-ks

Improve prefetching for table based implementations

110588 of 123708 relevant lines covered (89.39%)

11056434.37 hits per line

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

94.81
/src/lib/pubkey/ec_group/ec_inner_pc.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/internal/ec_inner_pc.h>
8

9
#include <botan/mem_ops.h>
10
#include <botan/internal/buffer_stuffer.h>
11

12
namespace Botan {
13

14
const EC_Scalar_Data_PC& EC_Scalar_Data_PC::checked_ref(const EC_Scalar_Data& data) {
306,455✔
15
   const auto* p = dynamic_cast<const EC_Scalar_Data_PC*>(&data);
306,455✔
16
   if(p == nullptr) {
306,455✔
17
      throw Invalid_State("Failed conversion to EC_Scalar_Data_PC");
×
18
   }
19
   return *p;
306,455✔
20
}
21

22
const std::shared_ptr<const EC_Group_Data>& EC_Scalar_Data_PC::group() const {
516,037✔
23
   return m_group;
80,018✔
24
}
25

26
size_t EC_Scalar_Data_PC::bytes() const {
105,904✔
27
   return this->group()->order_bytes();
105,904✔
28
}
29

30
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_PC::clone() const {
80,018✔
31
   return std::make_unique<EC_Scalar_Data_PC>(this->group(), this->value());
80,018✔
32
}
33

34
bool EC_Scalar_Data_PC::is_zero() const {
88,508✔
35
   const auto& pcurve = this->group()->pcurve();
88,508✔
36
   return pcurve.scalar_is_zero(m_v);
88,508✔
37
}
38

39
bool EC_Scalar_Data_PC::is_eq(const EC_Scalar_Data& other) const {
1,406✔
40
   const auto& pcurve = group()->pcurve();
1,406✔
41
   return pcurve.scalar_equal(m_v, checked_ref(other).m_v);
1,406✔
42
}
43

44
void EC_Scalar_Data_PC::assign(const EC_Scalar_Data& other) {
×
45
   BOTAN_STATE_CHECK(other.group() == this->group());
×
46
   m_v = checked_ref(other).value();
×
47
}
×
48

49
void EC_Scalar_Data_PC::zeroize() {
7,871✔
50
   m_v._zeroize();
7,871✔
51
}
7,871✔
52

53
void EC_Scalar_Data_PC::square_self() {
5,728✔
54
   // TODO square in place
55
   m_v = m_group->pcurve().scalar_square(m_v);
5,728✔
56
}
5,728✔
57

58
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_PC::negate() const {
12,820✔
59
   return std::make_unique<EC_Scalar_Data_PC>(m_group, m_group->pcurve().scalar_negate(m_v));
12,820✔
60
}
61

62
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_PC::invert() const {
15,522✔
63
   return std::make_unique<EC_Scalar_Data_PC>(m_group, m_group->pcurve().scalar_invert(m_v));
15,522✔
64
}
65

66
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_PC::invert_vartime() const {
35,494✔
67
   return std::make_unique<EC_Scalar_Data_PC>(m_group, m_group->pcurve().scalar_invert_vartime(m_v));
35,494✔
68
}
69

70
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_PC::add(const EC_Scalar_Data& other) const {
20,529✔
71
   return std::make_unique<EC_Scalar_Data_PC>(m_group, group()->pcurve().scalar_add(m_v, checked_ref(other).m_v));
20,529✔
72
}
73

74
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_PC::sub(const EC_Scalar_Data& other) const {
13,185✔
75
   return std::make_unique<EC_Scalar_Data_PC>(m_group, group()->pcurve().scalar_sub(m_v, checked_ref(other).m_v));
13,185✔
76
}
77

78
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_PC::mul(const EC_Scalar_Data& other) const {
121,617✔
79
   return std::make_unique<EC_Scalar_Data_PC>(m_group, group()->pcurve().scalar_mul(m_v, checked_ref(other).m_v));
121,617✔
80
}
81

82
void EC_Scalar_Data_PC::serialize_to(std::span<uint8_t> bytes) const {
108,749✔
83
   BOTAN_ARG_CHECK(bytes.size() == m_group->order_bytes(), "Invalid output length");
108,749✔
84
   m_group->pcurve().serialize_scalar(bytes, m_v);
108,749✔
85
}
108,749✔
86

87
EC_AffinePoint_Data_PC::EC_AffinePoint_Data_PC(std::shared_ptr<const EC_Group_Data> group,
112,589✔
88
                                               PCurve::PrimeOrderCurve::AffinePoint pt) :
112,589✔
89
      m_group(std::move(group)), m_pt(std::move(pt)) {
112,589✔
90
   const auto& pcurve = m_group->pcurve();
112,589✔
91

92
   if(!pcurve.affine_point_is_identity(m_pt)) {
112,589✔
93
      m_xy.resize(1 + 2 * field_element_bytes());
112,054✔
94
      pcurve.serialize_point(m_xy, m_pt);
112,054✔
95
   }
96
}
112,589✔
97

98
const EC_AffinePoint_Data_PC& EC_AffinePoint_Data_PC::checked_ref(const EC_AffinePoint_Data& data) {
48,055✔
99
   const auto* p = dynamic_cast<const EC_AffinePoint_Data_PC*>(&data);
48,055✔
100
   if(p == nullptr) {
48,055✔
101
      throw Invalid_State("Failed conversion to EC_AffinePoint_Data_PC");
×
102
   }
103
   return *p;
48,055✔
104
}
105

106
std::unique_ptr<EC_AffinePoint_Data> EC_AffinePoint_Data_PC::clone() const {
19,680✔
107
   return std::make_unique<EC_AffinePoint_Data_PC>(m_group, m_pt);
19,680✔
108
}
109

110
const std::shared_ptr<const EC_Group_Data>& EC_AffinePoint_Data_PC::group() const {
70,854✔
111
   return m_group;
70,854✔
112
}
113

114
std::unique_ptr<EC_AffinePoint_Data> EC_AffinePoint_Data_PC::mul(const EC_Scalar_Data& scalar,
14,928✔
115
                                                                 RandomNumberGenerator& rng) const {
116
   BOTAN_ARG_CHECK(scalar.group() == m_group, "Curve mismatch");
14,928✔
117
   const auto& k = EC_Scalar_Data_PC::checked_ref(scalar).value();
14,928✔
118
   const auto& pcurve = m_group->pcurve();
14,928✔
119
   auto pt = pcurve.point_to_affine(pcurve.mul(m_pt, k, rng));
14,928✔
120
   return std::make_unique<EC_AffinePoint_Data_PC>(m_group, std::move(pt));
14,928✔
121
}
14,928✔
122

123
secure_vector<uint8_t> EC_AffinePoint_Data_PC::mul_x_only(const EC_Scalar_Data& scalar,
5,097✔
124
                                                          RandomNumberGenerator& rng) const {
125
   BOTAN_ARG_CHECK(scalar.group() == m_group, "Curve mismatch");
5,097✔
126
   const auto& k = EC_Scalar_Data_PC::checked_ref(scalar).value();
5,097✔
127
   return m_group->pcurve().mul_x_only(m_pt, k, rng);
5,097✔
128
}
129

130
size_t EC_AffinePoint_Data_PC::field_element_bytes() const {
243,107✔
131
   return m_group->pcurve().field_element_bytes();
243,107✔
132
}
133

134
bool EC_AffinePoint_Data_PC::is_identity() const {
170,785✔
135
   return m_xy.empty();
170,785✔
136
}
137

138
void EC_AffinePoint_Data_PC::serialize_x_to(std::span<uint8_t> bytes) const {
11,789✔
139
   BOTAN_STATE_CHECK(!this->is_identity());
11,789✔
140
   const size_t fe_bytes = this->field_element_bytes();
11,789✔
141
   BOTAN_ARG_CHECK(bytes.size() == fe_bytes, "Invalid output size");
11,789✔
142
   copy_mem(bytes, std::span{m_xy}.subspan(1, fe_bytes));
11,789✔
143
}
11,789✔
144

145
void EC_AffinePoint_Data_PC::serialize_y_to(std::span<uint8_t> bytes) const {
86✔
146
   BOTAN_STATE_CHECK(!this->is_identity());
86✔
147
   const size_t fe_bytes = this->field_element_bytes();
86✔
148
   BOTAN_ARG_CHECK(bytes.size() == fe_bytes, "Invalid output size");
86✔
149
   copy_mem(bytes, std::span{m_xy}.subspan(1 + fe_bytes, fe_bytes));
86✔
150
}
86✔
151

152
void EC_AffinePoint_Data_PC::serialize_xy_to(std::span<uint8_t> bytes) const {
367✔
153
   BOTAN_STATE_CHECK(!this->is_identity());
367✔
154
   const size_t fe_bytes = this->field_element_bytes();
367✔
155
   BOTAN_ARG_CHECK(bytes.size() == 2 * fe_bytes, "Invalid output size");
367✔
156
   copy_mem(bytes, std::span{m_xy}.last(2 * fe_bytes));
367✔
157
}
367✔
158

159
void EC_AffinePoint_Data_PC::serialize_compressed_to(std::span<uint8_t> bytes) const {
10,846✔
160
   BOTAN_STATE_CHECK(!this->is_identity());
10,846✔
161
   const size_t fe_bytes = this->field_element_bytes();
10,846✔
162
   BOTAN_ARG_CHECK(bytes.size() == 1 + fe_bytes, "Invalid output size");
10,846✔
163
   const bool y_is_odd = (m_xy.back() & 0x01) == 0x01;
10,846✔
164

165
   BufferStuffer stuffer(bytes);
10,846✔
166
   stuffer.append(y_is_odd ? 0x03 : 0x02);
16,328✔
167
   this->serialize_x_to(stuffer.next(fe_bytes));
10,846✔
168
}
10,846✔
169

170
void EC_AffinePoint_Data_PC::serialize_uncompressed_to(std::span<uint8_t> bytes) const {
33,474✔
171
   BOTAN_STATE_CHECK(!this->is_identity());
33,474✔
172
   const size_t fe_bytes = this->field_element_bytes();
33,474✔
173
   BOTAN_ARG_CHECK(bytes.size() == 1 + 2 * fe_bytes, "Invalid output size");
33,474✔
174
   copy_mem(bytes, m_xy);
33,474✔
175
}
33,474✔
176

177
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
178
EC_Point EC_AffinePoint_Data_PC::to_legacy_point() const {
29,004✔
179
   if(this->is_identity()) {
29,004✔
180
      return EC_Point(m_group->curve());
216✔
181
   } else {
182
      const size_t fe_bytes = this->field_element_bytes();
28,788✔
183
      return EC_Point(m_group->curve(),
28,788✔
184
                      BigInt::from_bytes(std::span{m_xy}.subspan(1, fe_bytes)),
57,576✔
185
                      BigInt::from_bytes(std::span{m_xy}.last(fe_bytes)));
86,364✔
186
   }
187
}
188
#endif
189

190
EC_Mul2Table_Data_PC::EC_Mul2Table_Data_PC(const EC_AffinePoint_Data& q) : m_group(q.group()) {
14,130✔
191
   BOTAN_ARG_CHECK(q.group() == m_group, "Curve mismatch");
14,130✔
192

193
   const auto& pt_q = EC_AffinePoint_Data_PC::checked_ref(q);
14,130✔
194

195
   m_tbl = m_group->pcurve().mul2_setup_g(pt_q.value());
14,130✔
196
}
14,130✔
197

198
std::unique_ptr<EC_AffinePoint_Data> EC_Mul2Table_Data_PC::mul2_vartime(const EC_Scalar_Data& xd,
2,174✔
199
                                                                        const EC_Scalar_Data& yd) const {
200
   BOTAN_ARG_CHECK(xd.group() == m_group && yd.group() == m_group, "Curve mismatch");
2,174✔
201

202
   const auto& x = EC_Scalar_Data_PC::checked_ref(xd);
2,174✔
203
   const auto& y = EC_Scalar_Data_PC::checked_ref(yd);
2,174✔
204

205
   const auto& pcurve = m_group->pcurve();
2,174✔
206

207
   if(auto pt = pcurve.mul2_vartime(*m_tbl, x.value(), y.value())) {
2,174✔
208
      return std::make_unique<EC_AffinePoint_Data_PC>(m_group, pcurve.point_to_affine(*pt));
2,174✔
209
   } else {
210
      return nullptr;
×
211
   }
2,174✔
212
}
213

214
bool EC_Mul2Table_Data_PC::mul2_vartime_x_mod_order_eq(const EC_Scalar_Data& vd,
32,445✔
215
                                                       const EC_Scalar_Data& xd,
216
                                                       const EC_Scalar_Data& yd) const {
217
   BOTAN_ARG_CHECK(xd.group() == m_group && yd.group() == m_group, "Curve mismatch");
32,445✔
218

219
   const auto& v = EC_Scalar_Data_PC::checked_ref(vd);
32,445✔
220
   const auto& x = EC_Scalar_Data_PC::checked_ref(xd);
32,445✔
221
   const auto& y = EC_Scalar_Data_PC::checked_ref(yd);
32,445✔
222

223
   return m_group->pcurve().mul2_vartime_x_mod_order_eq(*m_tbl, v.value(), x.value(), y.value());
32,445✔
224
}
225

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