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

randombit / botan / 16313715143

16 Jul 2025 07:53AM UTC coverage: 90.629% (+0.006%) from 90.623%
16313715143

push

github

web-flow
Merge pull request #4991 from Rohde-Schwarz/fix/zeroize_pcurves_private_key

Scrub pcurves ECC private key values on destruction

99648 of 109952 relevant lines covered (90.63%)

12226975.4 hits per line

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

95.52
/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

11
namespace Botan {
12

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

21
const std::shared_ptr<const EC_Group_Data>& EC_Scalar_Data_PC::group() const {
161,223✔
22
   return m_group;
61,759✔
23
}
24

25
size_t EC_Scalar_Data_PC::bytes() const {
99,393✔
26
   return this->group()->order_bytes();
99,393✔
27
}
28

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

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

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

43
void EC_Scalar_Data_PC::assign(const EC_Scalar_Data& other) {
×
44
   m_v = checked_ref(other).value();
×
45
}
×
46

47
void EC_Scalar_Data_PC::zeroize() {
8,101✔
48
   m_v._zeroize();
8,101✔
49
}
8,101✔
50

51
void EC_Scalar_Data_PC::square_self() {
11,124✔
52
   // TODO square in place
53
   m_v = m_group->pcurve().scalar_square(m_v);
11,124✔
54
}
11,124✔
55

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

60
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_PC::invert() const {
17,214✔
61
   return std::make_unique<EC_Scalar_Data_PC>(m_group, m_group->pcurve().scalar_invert(m_v));
17,214✔
62
}
63

64
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_PC::invert_vartime() const {
26,460✔
65
   return std::make_unique<EC_Scalar_Data_PC>(m_group, m_group->pcurve().scalar_invert_vartime(m_v));
26,460✔
66
}
67

68
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_PC::add(const EC_Scalar_Data& other) const {
19,007✔
69
   return std::make_unique<EC_Scalar_Data_PC>(m_group, group()->pcurve().scalar_add(m_v, checked_ref(other).m_v));
19,007✔
70
}
71

72
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_PC::sub(const EC_Scalar_Data& other) const {
12,789✔
73
   return std::make_unique<EC_Scalar_Data_PC>(m_group, group()->pcurve().scalar_sub(m_v, checked_ref(other).m_v));
12,789✔
74
}
75

76
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_PC::mul(const EC_Scalar_Data& other) const {
113,342✔
77
   return std::make_unique<EC_Scalar_Data_PC>(m_group, group()->pcurve().scalar_mul(m_v, checked_ref(other).m_v));
113,342✔
78
}
79

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

85
EC_AffinePoint_Data_PC::EC_AffinePoint_Data_PC(std::shared_ptr<const EC_Group_Data> group,
103,723✔
86
                                               PCurve::PrimeOrderCurve::AffinePoint pt) :
103,723✔
87
      m_group(std::move(group)), m_pt(std::move(pt)) {
103,723✔
88
   const auto& pcurve = m_group->pcurve();
103,723✔
89

90
   if(!pcurve.affine_point_is_identity(m_pt)) {
103,723✔
91
      m_xy.resize(1 + 2 * field_element_bytes());
103,195✔
92
      pcurve.serialize_point(m_xy, m_pt);
103,195✔
93
   }
94
}
103,723✔
95

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

104
std::unique_ptr<EC_AffinePoint_Data> EC_AffinePoint_Data_PC::clone() const {
17,984✔
105
   return std::make_unique<EC_AffinePoint_Data_PC>(m_group, m_pt);
17,984✔
106
}
107

108
const std::shared_ptr<const EC_Group_Data>& EC_AffinePoint_Data_PC::group() const {
64,742✔
109
   return m_group;
64,742✔
110
}
111

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

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

128
size_t EC_AffinePoint_Data_PC::field_element_bytes() const {
222,302✔
129
   return m_group->pcurve().field_element_bytes();
222,302✔
130
}
131

132
bool EC_AffinePoint_Data_PC::is_identity() const {
154,129✔
133
   return m_xy.empty();
154,129✔
134
}
135

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

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

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

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

163
   BufferStuffer stuffer(bytes);
10,678✔
164
   stuffer.append(y_is_odd ? 0x03 : 0x02);
16,071✔
165
   this->serialize_x_to(stuffer.next(fe_bytes));
10,678✔
166
}
10,678✔
167

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

175
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
176
EC_Point EC_AffinePoint_Data_PC::to_legacy_point() const {
29,493✔
177
   if(this->is_identity()) {
29,493✔
178
      return EC_Point(m_group->curve());
216✔
179
   } else {
180
      const size_t fe_bytes = this->field_element_bytes();
29,277✔
181
      return EC_Point(m_group->curve(),
29,277✔
182
                      BigInt::from_bytes(std::span{m_xy}.subspan(1, fe_bytes)),
58,554✔
183
                      BigInt::from_bytes(std::span{m_xy}.last(fe_bytes)));
87,831✔
184
   }
185
}
186
#endif
187

188
EC_Mul2Table_Data_PC::EC_Mul2Table_Data_PC(const EC_AffinePoint_Data& q) : m_group(q.group()) {
14,657✔
189
   BOTAN_ARG_CHECK(q.group() == m_group, "Curve mismatch");
14,657✔
190

191
   const auto& pt_q = EC_AffinePoint_Data_PC::checked_ref(q);
14,657✔
192

193
   m_tbl = m_group->pcurve().mul2_setup_g(pt_q.value());
14,657✔
194
}
14,657✔
195

196
std::unique_ptr<EC_AffinePoint_Data> EC_Mul2Table_Data_PC::mul2_vartime(const EC_Scalar_Data& xd,
1,867✔
197
                                                                        const EC_Scalar_Data& yd) const {
198
   BOTAN_ARG_CHECK(xd.group() == m_group && yd.group() == m_group, "Curve mismatch");
1,867✔
199

200
   const auto& x = EC_Scalar_Data_PC::checked_ref(xd);
1,867✔
201
   const auto& y = EC_Scalar_Data_PC::checked_ref(yd);
1,867✔
202

203
   const auto& pcurve = m_group->pcurve();
1,867✔
204

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

212
bool EC_Mul2Table_Data_PC::mul2_vartime_x_mod_order_eq(const EC_Scalar_Data& vd,
23,363✔
213
                                                       const EC_Scalar_Data& xd,
214
                                                       const EC_Scalar_Data& yd) const {
215
   BOTAN_ARG_CHECK(xd.group() == m_group && yd.group() == m_group, "Curve mismatch");
23,363✔
216

217
   const auto& v = EC_Scalar_Data_PC::checked_ref(vd);
23,363✔
218
   const auto& x = EC_Scalar_Data_PC::checked_ref(xd);
23,363✔
219
   const auto& y = EC_Scalar_Data_PC::checked_ref(yd);
23,363✔
220

221
   return m_group->pcurve().mul2_vartime_x_mod_order_eq(*m_tbl, v.value(), x.value(), y.value());
23,363✔
222
}
223

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