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

randombit / botan / 13011071422

28 Jan 2025 01:04PM UTC coverage: 91.258% (+0.01%) from 91.248%
13011071422

push

github

web-flow
Merge pull request #4588 from randombit/jack/faster-redc-setup

Reduce overhead from computing modular reduction parameters

94083 of 103096 relevant lines covered (91.26%)

11357671.94 hits per line

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

94.76
/src/lib/pubkey/ec_group/ec_inner_data.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_data.h>
8

9
#include <botan/der_enc.h>
10
#include <botan/internal/ec_inner_pc.h>
11
#include <botan/internal/pcurves.h>
12

13
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
14
   #include <botan/internal/ec_inner_bn.h>
15
   #include <botan/internal/point_mul.h>
16
#endif
17

18
namespace Botan {
19

20
EC_Group_Data::~EC_Group_Data() = default;
13,963✔
21

22
// Note this constructor *does not* initialize m_curve, m_base_point or m_base_mult
23
EC_Group_Data::EC_Group_Data(const BigInt& p,
1,164✔
24
                             const BigInt& a,
25
                             const BigInt& b,
26
                             const BigInt& g_x,
27
                             const BigInt& g_y,
28
                             const BigInt& order,
29
                             const BigInt& cofactor,
30
                             const OID& oid,
31
                             EC_Group_Source source) :
1,164✔
32
      m_p(p),
1,164✔
33
      m_a(a),
1,164✔
34
      m_b(b),
1,164✔
35
      m_g_x(g_x),
1,164✔
36
      m_g_y(g_y),
1,164✔
37
      m_order(order),
1,164✔
38
      m_cofactor(cofactor),
1,164✔
39
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
40
      m_mod_field(Modular_Reducer::for_public_modulus(p)),
1,164✔
41
      m_mod_order(Modular_Reducer::for_public_modulus(order)),
1,164✔
42
      m_monty(m_p, m_mod_field),
1,164✔
43
#endif
44
      m_oid(oid),
1,164✔
45
      m_p_words(p.sig_words()),
1,164✔
46
      m_p_bits(p.bits()),
1,164✔
47
      m_order_bits(order.bits()),
1,164✔
48
      m_order_bytes((m_order_bits + 7) / 8),
1,164✔
49
      m_a_is_minus_3(a == p - 3),
2,328✔
50
      m_a_is_zero(a.is_zero()),
1,164✔
51
      m_has_cofactor(m_cofactor != 1),
1,164✔
52
      m_order_is_less_than_p(m_order < p),
1,164✔
53
      m_source(source) {
3,492✔
54
   if(!m_oid.empty()) {
1,164✔
55
      DER_Encoder der(m_der_named_curve);
1,153✔
56
      der.encode(m_oid);
1,153✔
57

58
      if(const auto id = PCurve::PrimeOrderCurveId::from_oid(m_oid)) {
1,153✔
59
         m_pcurve = PCurve::PrimeOrderCurve::from_id(*id);
913✔
60
         // still possibly null, if the curve is supported in general but not
61
         // available in the build
62
      }
63
   }
1,153✔
64

65
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
66
   secure_vector<word> ws;
1,164✔
67
   m_a_r = m_monty.mul(a, m_monty.R2(), ws);
2,328✔
68
   m_b_r = m_monty.mul(b, m_monty.R2(), ws);
2,328✔
69
#else
70
   if(!m_pcurve) {
71
      throw Not_Implemented("EC_Group this group is not supported unless legacy_ec_point is included in the build");
72
   }
73
#endif
74
}
1,164✔
75

76
std::shared_ptr<EC_Group_Data> EC_Group_Data::create(const BigInt& p,
1,164✔
77
                                                     const BigInt& a,
78
                                                     const BigInt& b,
79
                                                     const BigInt& g_x,
80
                                                     const BigInt& g_y,
81
                                                     const BigInt& order,
82
                                                     const BigInt& cofactor,
83
                                                     const OID& oid,
84
                                                     EC_Group_Source source) {
85
   auto group = std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, source);
1,164✔
86

87
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
88
   group->m_curve = CurveGFp(group.get());
1,164✔
89
   group->m_base_point = EC_Point(group->m_curve, g_x, g_y);
2,328✔
90
   if(!group->m_pcurve) {
1,164✔
91
      group->m_base_mult = std::make_unique<EC_Point_Base_Point_Precompute>(group->m_base_point, group->m_mod_order);
251✔
92
   }
93
#endif
94

95
   return group;
1,164✔
96
}
×
97

98
bool EC_Group_Data::params_match(const BigInt& p,
904✔
99
                                 const BigInt& a,
100
                                 const BigInt& b,
101
                                 const BigInt& g_x,
102
                                 const BigInt& g_y,
103
                                 const BigInt& order,
104
                                 const BigInt& cofactor) const {
105
   return (this->p() == p && this->a() == a && this->b() == b && this->order() == order &&
1,001✔
106
           this->cofactor() == cofactor && this->g_x() == g_x && this->g_y() == g_y);
992✔
107
}
108

109
bool EC_Group_Data::params_match(const EC_Group_Data& other) const {
20✔
110
   return params_match(other.p(), other.a(), other.b(), other.g_x(), other.g_y(), other.order(), other.cofactor());
20✔
111
}
112

113
void EC_Group_Data::set_oid(const OID& oid) {
6✔
114
   BOTAN_ARG_CHECK(!oid.empty(), "OID should be set");
6✔
115
   BOTAN_STATE_CHECK(m_oid.empty() && m_der_named_curve.empty());
6✔
116
   m_oid = oid;
6✔
117

118
   DER_Encoder der(m_der_named_curve);
6✔
119
   der.encode(m_oid);
6✔
120
}
6✔
121

122
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_with_trunc(std::span<const uint8_t> bytes) const {
26,067✔
123
   const size_t bit_length = 8 * bytes.size();
26,067✔
124

125
   if(bit_length < order_bits()) {
26,067✔
126
      // No shifting required, but might still need to reduce by modulus
127
      return this->scalar_from_bytes_mod_order(bytes);
5,252✔
128
   } else {
129
      const size_t shift = bit_length - order_bits();
20,815✔
130

131
      const size_t new_length = bytes.size() - (shift / 8);
20,815✔
132
      const size_t bit_shift = shift % 8;
20,815✔
133

134
      if(bit_shift == 0) {
20,815✔
135
         // Easy case just read different bytes
136
         return this->scalar_from_bytes_mod_order(bytes.first(new_length));
18,178✔
137
      } else {
138
         std::vector<uint8_t> sbytes(new_length);
2,637✔
139

140
         uint8_t carry = 0;
2,637✔
141
         for(size_t i = 0; i != new_length; ++i) {
72,196✔
142
            const uint8_t w = bytes[i];
69,559✔
143
            sbytes[i] = (w >> bit_shift) | carry;
69,559✔
144
            carry = w << (8 - bit_shift);
69,559✔
145
         }
146

147
         return this->scalar_from_bytes_mod_order(sbytes);
2,637✔
148
      }
2,637✔
149
   }
150
}
151

152
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_mod_order(std::span<const uint8_t> bytes) const {
34,780✔
153
   if(bytes.size() > 2 * order_bytes()) {
34,780✔
154
      return {};
×
155
   }
156

157
   if(m_pcurve) {
34,780✔
158
      if(auto s = m_pcurve->scalar_from_wide_bytes(bytes)) {
23,519✔
159
         return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), std::move(*s));
23,519✔
160
      } else {
161
         return {};
×
162
      }
23,519✔
163
   } else {
164
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
165
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(BigInt(bytes)));
22,522✔
166
#else
167
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
168
#endif
169
   }
170
}
171

172
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_random(RandomNumberGenerator& rng) const {
44,220✔
173
   if(m_pcurve) {
44,220✔
174
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->random_scalar(rng));
19,430✔
175
   } else {
176
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
177
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(),
49,580✔
178
                                                 BigInt::random_integer(rng, BigInt::one(), m_order));
99,160✔
179
#else
180
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
181
#endif
182
   }
183
}
184

185
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_zero() const {
×
186
   if(m_pcurve) {
×
187
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_zero());
×
188
   } else {
189
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
190
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::zero());
×
191
#else
192
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
193
#endif
194
   }
195
}
196

197
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_one() const {
101✔
198
   if(m_pcurve) {
101✔
199
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_one());
61✔
200
   } else {
201
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
202
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::one());
40✔
203
#else
204
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
205
#endif
206
   }
207
}
208

209
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bigint(const BigInt& bn) const {
4,485✔
210
   if(bn <= 0 || bn >= m_order) {
4,485✔
211
      return {};
×
212
   }
213

214
   if(m_pcurve) {
4,485✔
215
      return this->scalar_deserialize(bn.serialize(m_order_bytes));
6,754✔
216
   } else {
217
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
218
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), bn);
1,108✔
219
#else
220
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
221
#endif
222
   }
223
}
224

225
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::gk_x_mod_order(const EC_Scalar_Data& scalar,
3,308✔
226
                                                              RandomNumberGenerator& rng,
227
                                                              std::vector<BigInt>& ws) const {
228
   if(m_pcurve) {
3,308✔
229
      const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
1,687✔
230
      auto gk_x_mod_order = m_pcurve->base_point_mul_x_mod_order(k.value(), rng);
1,687✔
231
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), gk_x_mod_order);
1,687✔
232
   } else {
1,687✔
233
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
234
      const auto& k = EC_Scalar_Data_BN::checked_ref(scalar);
1,621✔
235
      BOTAN_STATE_CHECK(m_base_mult != nullptr);
1,621✔
236
      const auto pt = m_base_mult->mul(k.value(), rng, m_order, ws);
1,621✔
237

238
      if(pt.is_zero()) {
3,242✔
239
         return scalar_zero();
×
240
      } else {
241
         return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(pt.get_affine_x()));
3,242✔
242
      }
243
#else
244
      BOTAN_UNUSED(ws);
245
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
246
#endif
247
   }
1,621✔
248
}
249

250
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_deserialize(std::span<const uint8_t> bytes) const {
68,665✔
251
   if(bytes.size() != m_order_bytes) {
68,665✔
252
      return nullptr;
5,826✔
253
   }
254

255
   if(m_pcurve) {
62,839✔
256
      if(auto s = m_pcurve->deserialize_scalar(bytes)) {
46,885✔
257
         return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), *s);
44,679✔
258
      } else {
259
         return nullptr;
2,206✔
260
      }
46,885✔
261
   } else {
262
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
263
      BigInt r(bytes);
15,954✔
264

265
      if(r.is_zero() || r >= m_order) {
31,908✔
266
         return nullptr;
724✔
267
      }
268

269
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), std::move(r));
15,230✔
270
#else
271
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
272
#endif
273
   }
15,954✔
274
}
275

276
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_deserialize(std::span<const uint8_t> bytes) const {
44,408✔
277
   try {
44,408✔
278
      if(m_pcurve) {
44,408✔
279
         if(auto pt = m_pcurve->deserialize_point(bytes)) {
33,018✔
280
            return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(*pt));
26,901✔
281
         } else {
282
            return nullptr;
6,117✔
283
         }
33,018✔
284
      } else {
285
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
286
         return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), bytes);
11,648✔
287
#else
288
         throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
289
#endif
290
      }
291
   } catch(...) {
258✔
292
      return nullptr;
258✔
293
   }
258✔
294
}
295

296
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_ro(std::string_view hash_fn,
24✔
297
                                                                           std::span<const uint8_t> input,
298
                                                                           std::span<const uint8_t> domain_sep) const {
299
   if(m_pcurve) {
24✔
300
      auto pt = m_pcurve->hash_to_curve_ro(hash_fn, input, domain_sep);
24✔
301
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt.to_affine());
24✔
302
   } else {
24✔
303
      throw Not_Implemented("Hash to curve is not implemented for this curve");
×
304
   }
305
}
306

307
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_nu(std::string_view hash_fn,
33✔
308
                                                                           std::span<const uint8_t> input,
309
                                                                           std::span<const uint8_t> domain_sep) const {
310
   if(m_pcurve) {
33✔
311
      auto pt = m_pcurve->hash_to_curve_nu(hash_fn, input, domain_sep);
33✔
312
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
30✔
313
   } else {
30✔
314
      throw Not_Implemented("Hash to curve is not implemented for this curve");
×
315
   }
316
}
317

318
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_g_mul(const EC_Scalar_Data& scalar,
15,338✔
319
                                                                RandomNumberGenerator& rng,
320
                                                                std::vector<BigInt>& ws) const {
321
   if(m_pcurve) {
15,338✔
322
      const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
7,961✔
323
      auto pt = m_pcurve->mul_by_g(k.value(), rng).to_affine();
15,922✔
324
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
7,961✔
325
   } else {
7,961✔
326
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
327
      const auto& group = scalar.group();
7,377✔
328
      const auto& bn = EC_Scalar_Data_BN::checked_ref(scalar);
7,377✔
329

330
      BOTAN_STATE_CHECK(group->m_base_mult != nullptr);
7,377✔
331
      auto pt = group->m_base_mult->mul(bn.value(), rng, m_order, ws);
7,377✔
332
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
7,377✔
333
#else
334
      BOTAN_UNUSED(ws);
335
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
336
#endif
337
   }
7,377✔
338
}
339

340
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::mul_px_qy(const EC_AffinePoint_Data& p,
3,472✔
341
                                                              const EC_Scalar_Data& x,
342
                                                              const EC_AffinePoint_Data& q,
343
                                                              const EC_Scalar_Data& y,
344
                                                              RandomNumberGenerator& rng) const {
345
   if(m_pcurve) {
3,472✔
346
      auto pt = m_pcurve->mul_px_qy(EC_AffinePoint_Data_PC::checked_ref(p).value(),
5,208✔
347
                                    EC_Scalar_Data_PC::checked_ref(x).value(),
2,604✔
348
                                    EC_AffinePoint_Data_PC::checked_ref(q).value(),
2,604✔
349
                                    EC_Scalar_Data_PC::checked_ref(y).value(),
2,604✔
350
                                    rng);
2,604✔
351

352
      if(pt) {
2,604✔
353
         return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt->to_affine());
2,520✔
354
      } else {
355
         return nullptr;
84✔
356
      }
357
   } else {
2,604✔
358
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
359
      std::vector<BigInt> ws;
868✔
360
      const auto& group = p.group();
868✔
361

362
      // TODO this could be better!
363
      EC_Point_Var_Point_Precompute p_mul(p.to_legacy_point(), rng, ws);
868✔
364
      EC_Point_Var_Point_Precompute q_mul(q.to_legacy_point(), rng, ws);
868✔
365

366
      const auto order = group->order() * group->cofactor();  // See #3800
868✔
367

368
      auto px = p_mul.mul(EC_Scalar_Data_BN::checked_ref(x).value(), rng, order, ws);
868✔
369
      auto qy = q_mul.mul(EC_Scalar_Data_BN::checked_ref(y).value(), rng, order, ws);
868✔
370

371
      auto px_qy = px + qy;
868✔
372

373
      if(!px_qy.is_zero()) {
1,624✔
374
         px_qy.force_affine();
756✔
375
         return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(px_qy));
756✔
376
      } else {
377
         return nullptr;
112✔
378
      }
379
#else
380
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
381
#endif
382
   }
3,472✔
383
}
384

385
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::affine_add(const EC_AffinePoint_Data& p,
7,753✔
386
                                                               const EC_AffinePoint_Data& q) const {
387
   if(m_pcurve) {
7,753✔
388
      auto pt = m_pcurve->point_add_mixed(
5,045✔
389
         PCurve::PrimeOrderCurve::ProjectivePoint::from_affine(EC_AffinePoint_Data_PC::checked_ref(p).value()),
5,046✔
390
         EC_AffinePoint_Data_PC::checked_ref(q).value());
10,090✔
391

392
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt.to_affine());
5,044✔
393
   } else {
5,044✔
394
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
395
      auto pt = p.to_legacy_point() + q.to_legacy_point();
2,708✔
396
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
2,708✔
397
#else
398
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
399
#endif
400
   }
2,708✔
401
}
402

403
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::affine_neg(const EC_AffinePoint_Data& p) const {
9,512✔
404
   if(m_pcurve) {
9,512✔
405
      auto pt = m_pcurve->point_negate(EC_AffinePoint_Data_PC::checked_ref(p).value());
6,312✔
406
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt);
6,312✔
407
   } else {
6,312✔
408
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
409
      auto pt = p.to_legacy_point();
3,200✔
410
      pt.negate();  // negates in place
3,200✔
411
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
3,200✔
412
#else
413
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
414
#endif
415
   }
3,200✔
416
}
417

418
std::unique_ptr<EC_Mul2Table_Data> EC_Group_Data::make_mul2_table(const EC_AffinePoint_Data& h) const {
13,254✔
419
   if(m_pcurve) {
13,254✔
420
      EC_AffinePoint_Data_PC g(shared_from_this(), m_pcurve->generator());
22,346✔
421
      return std::make_unique<EC_Mul2Table_Data_PC>(g, h);
11,173✔
422
   } else {
11,173✔
423
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
424
      EC_AffinePoint_Data_BN g(shared_from_this(), this->base_point());
4,162✔
425
      return std::make_unique<EC_Mul2Table_Data_BN>(g, h);
2,081✔
426
#else
427
      throw Not_Implemented("Legacy EC interfaces disabled in this build configuration");
428
#endif
429
   }
2,081✔
430
}
431

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