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

randombit / botan / 15809386241

22 Jun 2025 06:05PM UTC coverage: 90.559% (-0.003%) from 90.562%
15809386241

Pull #4936

github

web-flow
Merge b66ec2a5e into 57448f644
Pull Request #4936: Improve docs regarding building universal binaries for macOS [ci skip]

98794 of 109094 relevant lines covered (90.56%)

12363629.72 hits per line

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

96.48
/src/lib/math/pcurves/pcurves_generic/pcurves_generic.cpp
1
/*
2
* (C) 2025 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include <botan/internal/pcurves_generic.h>
8

9
#include <botan/bigint.h>
10
#include <botan/exceptn.h>
11
#include <botan/rng.h>
12
#include <botan/internal/ct_utils.h>
13
#include <botan/internal/loadstor.h>
14
#include <botan/internal/mp_core.h>
15
#include <botan/internal/pcurves_algos.h>
16
#include <botan/internal/pcurves_instance.h>
17
#include <botan/internal/pcurves_mul.h>
18
#include <botan/internal/primality.h>
19
#include <algorithm>
20

21
namespace Botan::PCurve {
22

23
namespace {
24

25
template <size_t N>
26
constexpr std::optional<std::array<word, N>> bytes_to_words(std::span<const uint8_t> bytes) {
115,622✔
27
   if(bytes.size() > WordInfo<word>::bytes * N) {
115,622✔
28
      return std::nullopt;
×
29
   }
30

31
   std::array<word, N> r = {};
115,622✔
32

33
   const size_t full_words = bytes.size() / WordInfo<word>::bytes;
115,622✔
34
   const size_t extra_bytes = bytes.size() % WordInfo<word>::bytes;
115,622✔
35

36
   for(size_t i = 0; i != full_words; ++i) {
664,774✔
37
      r[i] = load_be<word>(bytes.data(), full_words - 1 - i);
549,152✔
38
   }
39

40
   if(extra_bytes > 0) {
115,622✔
41
      const size_t shift = extra_bytes * 8;
43,804✔
42
      bigint_shl1(r.data(), r.size(), r.size(), shift);
43,804✔
43

44
      for(size_t i = 0; i != extra_bytes; ++i) {
262,304✔
45
         const word b0 = bytes[WordInfo<word>::bytes * full_words + i];
218,500✔
46
         r[0] |= (b0 << (8 * (extra_bytes - 1 - i)));
218,500✔
47
      }
48
   }
49

50
   return r;
115,622✔
51
}
52

53
template <typename T>
54
T impl_pow_vartime(const T& elem, const T& one, size_t bits, std::span<const word> exp) {
46,527✔
55
   constexpr size_t WindowBits = 4;
46,527✔
56
   constexpr size_t WindowElements = (1 << WindowBits) - 1;
46,527✔
57

58
   const size_t Windows = (bits + WindowBits - 1) / WindowBits;
46,527✔
59

60
   std::vector<T> tbl;
46,527✔
61
   tbl.reserve(WindowElements);
46,527✔
62

63
   tbl.push_back(elem);
46,527✔
64

65
   for(size_t i = 1; i != WindowElements; ++i) {
697,905✔
66
      if(i % 2 == 1) {
651,378✔
67
         tbl.push_back(tbl[i / 2].square());
651,378✔
68
      } else {
69
         tbl.push_back(tbl[i - 1] * tbl[0]);
651,378✔
70
      }
71
   }
72

73
   auto r = one;
46,527✔
74

75
   const size_t w0 = read_window_bits<WindowBits>(exp, (Windows - 1) * WindowBits);
46,527✔
76

77
   if(w0 > 0) {
46,527✔
78
      r = tbl[w0 - 1];
46,527✔
79
   }
80

81
   for(size_t i = 1; i != Windows; ++i) {
2,837,632✔
82
      for(size_t j = 0; j != WindowBits; ++j) {
13,955,525✔
83
         r = r.square();
11,164,420✔
84
      }
85
      const size_t w = read_window_bits<WindowBits>(exp, (Windows - i - 1) * WindowBits);
2,791,105✔
86

87
      if(w > 0) {
2,791,105✔
88
         r *= tbl[w - 1];
2,610,739✔
89
      }
90
   }
91

92
   return r;
46,527✔
93
}
46,527✔
94

95
}  // namespace
96

97
class GenericCurveParams final {
145✔
98
   public:
99
      typedef PrimeOrderCurve::StorageUnit StorageUnit;
100
      static constexpr size_t N = PrimeOrderCurve::StorageWords;
101

102
      GenericCurveParams(const BigInt& p,
145✔
103
                         const BigInt& a,
104
                         const BigInt& b,
105
                         const BigInt& base_x,
106
                         const BigInt& base_y,
107
                         const BigInt& order) :
145✔
108
            m_words(p.sig_words()),
145✔
109
            m_order_bits(order.bits()),
145✔
110
            m_order_bytes(order.bytes()),
145✔
111
            m_field_bits(p.bits()),
145✔
112
            m_field_bytes(p.bytes()),
145✔
113
            m_monty_order(order),
145✔
114
            m_monty_field(p),
145✔
115
            m_field(bn_to_fixed(p)),
145✔
116
            m_field_minus_2(bn_to_fixed_rev(p - 2)),
145✔
117
            m_field_monty_r1(bn_to_fixed(m_monty_field.R1())),
145✔
118
            m_field_monty_r2(bn_to_fixed(m_monty_field.R2())),
145✔
119
            m_field_p_plus_1_over_4(bn_to_fixed_rev((p + 1) / 4)),
145✔
120
            m_field_p_over_2_plus_1(bn_to_fixed((p / 2) + 1)),
290✔
121
            m_field_p_dash(m_monty_field.p_dash()),
145✔
122

123
            m_order(bn_to_fixed(order)),
145✔
124
            m_order_minus_2(bn_to_fixed_rev(order - 2)),
145✔
125
            m_order_monty_r1(bn_to_fixed(m_monty_order.R1())),
145✔
126
            m_order_monty_r2(bn_to_fixed(m_monty_order.R2())),
145✔
127
            m_order_monty_r3(bn_to_fixed(m_monty_order.R3())),
145✔
128
            m_order_p_dash(m_monty_order.p_dash()),
145✔
129

130
            m_a_is_minus_3(a + 3 == p),
145✔
131
            m_a_is_zero(a.is_zero()),
145✔
132
            m_order_is_lt_field(order < p) {
145✔
133
         secure_vector<word> ws;
145✔
134
         m_monty_curve_a = bn_to_fixed(m_monty_field.mul(a, m_monty_field.R2(), ws));
145✔
135
         m_monty_curve_b = bn_to_fixed(m_monty_field.mul(b, m_monty_field.R2(), ws));
145✔
136

137
         m_base_x = bn_to_fixed(m_monty_field.mul(base_x, m_monty_field.R2(), ws));
145✔
138
         m_base_y = bn_to_fixed(m_monty_field.mul(base_y, m_monty_field.R2(), ws));
145✔
139
      }
145✔
140

141
      size_t words() const { return m_words; }
8,435,141✔
142

143
      size_t order_bits() const { return m_order_bits; }
48,376✔
144

145
      size_t order_bytes() const { return m_order_bytes; }
75,814✔
146

147
      size_t field_bits() const { return m_field_bits; }
86,311✔
148

149
      size_t field_bytes() const { return m_field_bytes; }
54,818✔
150

151
      const Montgomery_Params& monty_order() const { return m_monty_order; }
152

153
      const Montgomery_Params& monty_field() const { return m_monty_field; }
154

155
      const StorageUnit& field() const { return m_field; }
59,480,794✔
156

157
      const StorageUnit& field_minus_2() const { return m_field_minus_2; }
32,268✔
158

159
      const StorageUnit& field_monty_r1() const { return m_field_monty_r1; }
160

161
      const StorageUnit& field_monty_r2() const { return m_field_monty_r2; }
71,225✔
162

163
      const StorageUnit& field_p_plus_1_over_4() const { return m_field_p_plus_1_over_4; }
2,871✔
164

165
      const StorageUnit& field_p_over_2_plus_1() const { return m_field_p_over_2_plus_1; }
869,712✔
166

167
      word field_p_dash() const { return m_field_p_dash; }
59,871,054✔
168

169
      const StorageUnit& order() const { return m_order; }
59,961✔
170

171
      const StorageUnit& order_minus_2() const { return m_order_minus_2; }
11,388✔
172

173
      const StorageUnit& order_monty_r1() const { return m_order_monty_r1; }
174

175
      const StorageUnit& order_monty_r2() const { return m_order_monty_r2; }
30,679✔
176

177
      const StorageUnit& order_monty_r3() const { return m_order_monty_r3; }
9,640✔
178

179
      word order_p_dash() const { return m_order_p_dash; }
3,751,425✔
180

181
      const StorageUnit& monty_curve_a() const { return m_monty_curve_a; }
182

183
      const StorageUnit& monty_curve_b() const { return m_monty_curve_b; }
184

185
      const StorageUnit& base_x() const { return m_base_x; }
186

187
      const StorageUnit& base_y() const { return m_base_y; }
188

189
      bool a_is_minus_3() const { return m_a_is_minus_3; }
1,075,134✔
190

191
      bool a_is_zero() const { return m_a_is_zero; }
553,217✔
192

193
      bool order_is_less_than_field() const { return m_order_is_lt_field; }
2,380✔
194

195
      void mul(std::array<word, 2 * N>& z, const std::array<word, N>& x, const std::array<word, N>& y) const {
31,808,623✔
196
         clear_mem(z);
31,808,623✔
197

198
         if(m_words == 4) {
31,808,623✔
199
            bigint_comba_mul4(z.data(), x.data(), y.data());
12,879,568✔
200
         } else if(m_words == 6) {
18,929,055✔
201
            bigint_comba_mul6(z.data(), x.data(), y.data());
102,766✔
202
         } else if(m_words == 8) {
18,826,289✔
203
            bigint_comba_mul8(z.data(), x.data(), y.data());
3,652,354✔
204
         } else if(m_words == 9) {
15,173,935✔
205
            bigint_comba_mul9(z.data(), x.data(), y.data());
×
206
         } else {
207
            bigint_mul(z.data(), z.size(), x.data(), m_words, m_words, y.data(), m_words, m_words, nullptr, 0);
15,173,935✔
208
         }
209
      }
31,808,623✔
210

211
      void sqr(std::array<word, 2 * N>& z, const std::array<word, N>& x) const {
31,684,534✔
212
         clear_mem(z);
31,684,534✔
213

214
         if(m_words == 4) {
31,684,534✔
215
            bigint_comba_sqr4(z.data(), x.data());
13,193,090✔
216
         } else if(m_words == 6) {
18,491,444✔
217
            bigint_comba_sqr6(z.data(), x.data());
45,620✔
218
         } else if(m_words == 8) {
18,445,824✔
219
            bigint_comba_sqr8(z.data(), x.data());
4,161,481✔
220
         } else if(m_words == 9) {
14,284,343✔
221
            bigint_comba_sqr9(z.data(), x.data());
×
222
         } else {
223
            bigint_sqr(z.data(), z.size(), x.data(), m_words, m_words, nullptr, 0);
14,284,343✔
224
         }
225
      }
31,684,534✔
226

227
   private:
228
      static std::array<word, PrimeOrderCurve::StorageWords> bn_to_fixed(const BigInt& n) {
2,175✔
229
         const size_t n_words = n.sig_words();
2,175✔
230
         BOTAN_ASSERT_NOMSG(n_words <= PrimeOrderCurve::StorageWords);
2,175✔
231

232
         std::array<word, PrimeOrderCurve::StorageWords> r = {};
2,175✔
233
         copy_mem(std::span{r}.first(n_words), n._as_span().first(n_words));
2,175✔
234
         return r;
2,175✔
235
      }
2,175✔
236

237
      static std::array<word, PrimeOrderCurve::StorageWords> bn_to_fixed_rev(const BigInt& n) {
435✔
238
         auto v = bn_to_fixed(n);
435✔
239
         std::reverse(v.begin(), v.end());
435✔
240
         return v;
435✔
241
      }
242

243
   private:
244
      size_t m_words;
245
      size_t m_order_bits;
246
      size_t m_order_bytes;
247
      size_t m_field_bits;
248
      size_t m_field_bytes;
249

250
      Montgomery_Params m_monty_order;
251
      Montgomery_Params m_monty_field;
252

253
      StorageUnit m_field;
254
      StorageUnit m_field_minus_2;
255
      StorageUnit m_field_monty_r1;
256
      StorageUnit m_field_monty_r2;
257
      StorageUnit m_field_p_plus_1_over_4;
258
      StorageUnit m_field_p_over_2_plus_1;
259
      word m_field_p_dash;
260

261
      StorageUnit m_order;
262
      StorageUnit m_order_minus_2;
263
      StorageUnit m_order_monty_r1;
264
      StorageUnit m_order_monty_r2;
265
      StorageUnit m_order_monty_r3;
266
      word m_order_p_dash;
267

268
      StorageUnit m_monty_curve_a;
269
      StorageUnit m_monty_curve_b;
270

271
      StorageUnit m_base_x;
272
      StorageUnit m_base_y;
273

274
      bool m_a_is_minus_3;
275
      bool m_a_is_zero;
276
      bool m_order_is_lt_field;
277
};
278

279
class GenericScalar final {
280
   public:
281
      typedef word W;
282
      typedef PrimeOrderCurve::StorageUnit StorageUnit;
283
      static constexpr size_t N = PrimeOrderCurve::StorageWords;
284

285
      static std::optional<GenericScalar> from_wide_bytes(const GenericPrimeOrderCurve* curve,
9,640✔
286
                                                          std::span<const uint8_t> bytes) {
287
         const size_t mlen = curve->_params().order_bytes();
9,640✔
288

289
         if(bytes.size() > 2 * mlen) {
9,640✔
290
            return {};
×
291
         }
292

293
         std::array<uint8_t, 2 * sizeof(word) * N> padded_bytes = {};
9,640✔
294
         copy_mem(std::span{padded_bytes}.last(bytes.size()), bytes);
9,640✔
295

296
         auto words = bytes_to_words<2 * N>(std::span{padded_bytes});
9,640✔
297
         if(words) {
9,640✔
298
            auto in_rep = wide_to_rep(curve, words.value());
9,640✔
299
            return GenericScalar(curve, in_rep);
9,640✔
300
         } else {
301
            return {};
×
302
         }
303
      }
9,640✔
304

305
      static std::optional<GenericScalar> deserialize(const GenericPrimeOrderCurve* curve,
32,144✔
306
                                                      std::span<const uint8_t> bytes) {
307
         const size_t len = curve->_params().order_bytes();
32,144✔
308

309
         if(bytes.size() != len) {
32,144✔
310
            return {};
×
311
         }
312

313
         const auto words = bytes_to_words<N>(bytes);
32,144✔
314

315
         if(words) {
32,144✔
316
            if(!bigint_ct_is_lt(words->data(), N, curve->_params().order().data(), N).as_bool()) {
32,144✔
317
               return {};
1,465✔
318
            }
319

320
            // Safe because we checked above that words is an integer < P
321
            return GenericScalar(curve, to_rep(curve, *words));
30,679✔
322
         } else {
323
            return {};
×
324
         }
325
      }
326

327
      static GenericScalar zero(const GenericPrimeOrderCurve* curve) {
328
         StorageUnit zeros = {};
329
         return GenericScalar(curve, zeros);
330
      }
331

332
      static GenericScalar one(const GenericPrimeOrderCurve* curve) {
11,432✔
333
         return GenericScalar(curve, curve->_params().order_monty_r1());
11,432✔
334
      }
335

336
      static GenericScalar random(const GenericPrimeOrderCurve* curve, RandomNumberGenerator& rng) {
18,627✔
337
         constexpr size_t MAX_ATTEMPTS = 1000;
18,627✔
338

339
         const size_t bits = curve->_params().order_bits();
18,627✔
340

341
         std::vector<uint8_t> buf(curve->_params().order_bytes());
18,627✔
342

343
         for(size_t i = 0; i != MAX_ATTEMPTS; ++i) {
19,878✔
344
            rng.randomize(buf);
19,878✔
345

346
            // Zero off high bits that if set would certainly cause us
347
            // to be out of range
348
            if(bits % 8 != 0) {
19,878✔
349
               const uint8_t mask = 0xFF >> (8 - (bits % 8));
4,638✔
350
               buf[0] &= mask;
4,638✔
351
            }
352

353
            if(auto s = GenericScalar::deserialize(curve, buf)) {
19,878✔
354
               if(s.value().is_nonzero().as_bool()) {
18,627✔
355
                  return s.value();
18,627✔
356
               }
357
            }
358
         }
359

360
         throw Internal_Error("Failed to generate random Scalar within bounded number of attempts");
×
361
      }
18,627✔
362

363
      friend GenericScalar operator+(const GenericScalar& a, const GenericScalar& b) {
14,023✔
364
         auto curve = check_curve(a, b);
28,046✔
365
         const size_t words = curve->_params().words();
14,023✔
366

367
         StorageUnit t = {};
14,023✔
368
         W carry = bigint_add3_nc(t.data(), a.data(), words, b.data(), words);
28,046✔
369

370
         StorageUnit r = {};
14,023✔
371
         bigint_monty_maybe_sub(words, r.data(), carry, t.data(), curve->_params().order().data());
14,023✔
372
         return GenericScalar(curve, r);
14,023✔
373
      }
374

375
      friend GenericScalar operator-(const GenericScalar& a, const GenericScalar& b) { return a + b.negate(); }
6,289✔
376

377
      friend GenericScalar operator*(const GenericScalar& a, const GenericScalar& b) {
109,686✔
378
         auto curve = check_curve(a, b);
219,372✔
379

380
         std::array<W, 2 * N> z;
109,686✔
381
         curve->_params().mul(z, a.value(), b.value());
109,686✔
382
         return GenericScalar(curve, redc(curve, z));
109,686✔
383
      }
384

385
      GenericScalar& operator*=(const GenericScalar& other) {
658,941✔
386
         auto curve = check_curve(*this, other);
1,317,882✔
387

388
         std::array<W, 2 * N> z;
658,941✔
389
         curve->_params().mul(z, value(), other.value());
658,941✔
390
         m_val = redc(curve, z);
658,941✔
391
         return (*this);
658,941✔
392
      }
393

394
      GenericScalar square() const {
2,862,204✔
395
         auto curve = this->m_curve;
2,862,204✔
396

397
         std::array<W, 2 * N> z;
2,862,204✔
398
         curve->_params().sqr(z, value());
2,862,204✔
399
         return GenericScalar(curve, redc(curve, z));
2,862,204✔
400
      }
401

402
      GenericScalar pow_vartime(const StorageUnit& exp) const {
11,388✔
403
         auto one = GenericScalar::one(curve());
11,388✔
404
         auto bits = curve()->_params().order_bits();
11,388✔
405
         auto words = curve()->_params().words();
11,388✔
406
         return impl_pow_vartime(*this, one, bits, std::span{exp}.last(words));
22,776✔
407
      }
408

409
      GenericScalar negate() const {
11,587✔
410
         auto x_is_zero = CT::all_zeros(this->data(), N);
23,174✔
411

412
         StorageUnit r;
11,587✔
413
         bigint_sub3(r.data(), m_curve->_params().order().data(), N, this->data(), N);
11,587✔
414
         x_is_zero.if_set_zero_out(r.data(), N);
11,587✔
415
         return GenericScalar(m_curve, r);
11,587✔
416
      }
417

418
      GenericScalar invert() const { return pow_vartime(m_curve->_params().order_minus_2()); }
11,388✔
419

420
      template <concepts::resizable_byte_buffer T>
421
      T serialize() const {
13,590✔
422
         T bytes(m_curve->_params().order_bytes());
13,590✔
423
         this->serialize_to(bytes);
13,590✔
424
         return bytes;
13,590✔
425
      }
×
426

427
      void serialize_to(std::span<uint8_t> bytes) const {
57,187✔
428
         auto v = from_rep(m_curve, m_val);
57,187✔
429
         std::reverse(v.begin(), v.end());
57,187✔
430

431
         const size_t flen = m_curve->_params().order_bytes();
57,187✔
432
         BOTAN_ARG_CHECK(bytes.size() == flen, "Expected output span provided");
57,187✔
433

434
         // Remove leading zero bytes
435
         const auto padded_bytes = store_be(v);
57,187✔
436
         const size_t extra = N * WordInfo<W>::bytes - flen;
57,187✔
437
         copy_mem(bytes, std::span{padded_bytes}.subspan(extra, flen));
57,187✔
438
      }
57,187✔
439

440
      CT::Choice is_zero() const { return CT::all_zeros(m_val.data(), m_curve->_params().words()).as_choice(); }
32,102✔
441

442
      CT::Choice is_nonzero() const { return !is_zero(); }
18,627✔
443

444
      CT::Choice operator==(const GenericScalar& other) const {
1,536✔
445
         if(this->m_curve != other.m_curve) {
1,536✔
446
            return CT::Choice::no();
×
447
         }
448

449
         return CT::is_equal(m_val.data(), other.m_val.data(), m_curve->_params().words()).as_choice();
1,536✔
450
      }
451

452
      /**
453
      * Convert the integer to standard representation and return the sequence of words
454
      */
455
      StorageUnit to_words() const { return from_rep(m_curve, m_val); }
13,448✔
456

457
      const StorageUnit& stash_value() const { return m_val; }
458

459
      const GenericPrimeOrderCurve* curve() const { return m_curve; }
11,388✔
460

461
      GenericScalar(const GenericPrimeOrderCurve* curve, StorageUnit val) : m_curve(curve), m_val(val) {}
51,751✔
462

463
   private:
464
      const StorageUnit& value() const { return m_val; }
3,630,831✔
465

466
      const W* data() const { return m_val.data(); }
37,197✔
467

468
      static const GenericPrimeOrderCurve* check_curve(const GenericScalar& a, const GenericScalar& b) {
782,650✔
469
         BOTAN_STATE_CHECK(a.m_curve == b.m_curve);
782,650✔
470
         return a.m_curve;
782,650✔
471
      }
472

473
      static StorageUnit redc(const GenericPrimeOrderCurve* curve, std::array<W, 2 * N> z) {
3,751,425✔
474
         const auto& mod = curve->_params().order();
3,751,425✔
475
         const size_t words = curve->_params().words();
3,751,425✔
476
         StorageUnit r = {};
3,751,425✔
477
         StorageUnit ws = {};
3,751,425✔
478
         bigint_monty_redc(
3,751,425✔
479
            r.data(), z.data(), mod.data(), words, curve->_params().order_p_dash(), ws.data(), ws.size());
3,751,425✔
480
         return r;
3,751,425✔
481
      }
482

483
      static StorageUnit from_rep(const GenericPrimeOrderCurve* curve, StorageUnit z) {
70,635✔
484
         std::array<W, 2 * N> ze = {};
70,635✔
485
         copy_mem(std::span{ze}.template first<N>(), z);
70,635✔
486
         return redc(curve, ze);
70,635✔
487
      }
70,635✔
488

489
      static StorageUnit to_rep(const GenericPrimeOrderCurve* curve, StorageUnit x) {
30,679✔
490
         std::array<W, 2 * N> z;
30,679✔
491
         curve->_params().mul(z, x, curve->_params().order_monty_r2());
30,679✔
492
         return redc(curve, z);
30,679✔
493
      }
494

495
      static StorageUnit wide_to_rep(const GenericPrimeOrderCurve* curve, std::array<W, 2 * N> x) {
9,640✔
496
         auto redc_x = redc(curve, x);
9,640✔
497
         std::array<W, 2 * N> z;
9,640✔
498
         curve->_params().mul(z, redc_x, curve->_params().order_monty_r3());
9,640✔
499
         return redc(curve, z);
9,640✔
500
      }
501

502
      const GenericPrimeOrderCurve* m_curve;
503
      StorageUnit m_val;
504
};
505

506
class GenericField final {
507
   public:
508
      typedef word W;
509
      typedef PrimeOrderCurve::StorageUnit StorageUnit;
510
      static constexpr size_t N = PrimeOrderCurve::StorageWords;
511

512
      static std::optional<GenericField> deserialize(const GenericPrimeOrderCurve* curve,
73,838✔
513
                                                     std::span<const uint8_t> bytes) {
514
         const size_t len = curve->_params().field_bytes();
73,838✔
515

516
         if(bytes.size() != len) {
73,838✔
517
            return {};
×
518
         }
519

520
         const auto words = bytes_to_words<N>(bytes);
73,838✔
521

522
         if(words) {
73,838✔
523
            if(!bigint_ct_is_lt(words->data(), N, curve->_params().field().data(), N).as_bool()) {
73,838✔
524
               return {};
4,820✔
525
            }
526

527
            // Safe because we checked above that words is an integer < P
528
            return GenericField::from_words(curve, *words);
69,018✔
529
         } else {
530
            return {};
×
531
         }
532
      }
533

534
      static GenericField from_words(const GenericPrimeOrderCurve* curve, const std::array<word, N>& words) {
71,225✔
535
         return GenericField(curve, to_rep(curve, words));
71,225✔
536
      }
537

538
      static GenericField zero(const GenericPrimeOrderCurve* curve) {
925,547✔
539
         StorageUnit zeros = {};
925,547✔
540
         return GenericField(curve, zeros);
925,547✔
541
      }
542

543
      static GenericField one(const GenericPrimeOrderCurve* curve) {
1,447,243✔
544
         return GenericField(curve, curve->_params().field_monty_r1());
1,447,243✔
545
      }
546

547
      static GenericField curve_a(const GenericPrimeOrderCurve* curve) {
464,464✔
548
         return GenericField(curve, curve->_params().monty_curve_a());
464,464✔
549
      }
550

551
      static GenericField curve_b(const GenericPrimeOrderCurve* curve) {
20,231✔
552
         return GenericField(curve, curve->_params().monty_curve_b());
20,231✔
553
      }
554

555
      static GenericField random(const GenericPrimeOrderCurve* curve, RandomNumberGenerator& rng) {
51,172✔
556
         constexpr size_t MAX_ATTEMPTS = 1000;
51,172✔
557

558
         const size_t bits = curve->_params().field_bits();
51,172✔
559

560
         std::vector<uint8_t> buf(curve->_params().field_bytes());
51,172✔
561

562
         for(size_t i = 0; i != MAX_ATTEMPTS; ++i) {
55,992✔
563
            rng.randomize(buf);
55,992✔
564

565
            // Zero off high bits that if set would certainly cause us
566
            // to be out of range
567
            if(bits % 8 != 0) {
55,992✔
568
               const uint8_t mask = 0xFF >> (8 - (bits % 8));
10,812✔
569
               buf[0] &= mask;
10,812✔
570
            }
571

572
            if(auto s = GenericField::deserialize(curve, buf)) {
55,992✔
573
               if(s.value().is_nonzero().as_bool()) {
51,172✔
574
                  return s.value();
51,172✔
575
               }
576
            }
577
         }
578

579
         throw Internal_Error("Failed to generate random Scalar within bounded number of attempts");
×
580
      }
51,172✔
581

582
      /**
583
      * Return the value of this divided by 2
584
      */
585
      GenericField div2() const {
869,712✔
586
         StorageUnit t = value();
869,712✔
587
         W borrow = shift_right<1>(t);
869,712✔
588

589
         // If value was odd, add (P/2)+1
590
         bigint_cnd_add(borrow, t.data(), N, m_curve->_params().field_p_over_2_plus_1().data(), N);
869,712✔
591

592
         return GenericField(m_curve, t);
869,712✔
593
      }
594

595
      /// Return (*this) multiplied by 2
596
      GenericField mul2() const {
11,604,747✔
597
         StorageUnit t = value();
11,604,747✔
598
         W carry = shift_left<1>(t);
11,604,747✔
599

600
         StorageUnit r;
11,604,747✔
601
         bigint_monty_maybe_sub<N>(r.data(), carry, t.data(), m_curve->_params().field().data());
11,604,747✔
602
         return GenericField(m_curve, r);
11,604,747✔
603
      }
604

605
      /// Return (*this) multiplied by 3
606
      GenericField mul3() const { return mul2() + (*this); }
3,235,975✔
607

608
      /// Return (*this) multiplied by 4
609
      GenericField mul4() const { return mul2().mul2(); }
205,422✔
610

611
      /// Return (*this) multiplied by 8
612
      GenericField mul8() const { return mul2().mul2().mul2(); }
205,422✔
613

614
      friend GenericField operator+(const GenericField& a, const GenericField& b) {
27,068,502✔
615
         auto curve = check_curve(a, b);
54,137,004✔
616
         const size_t words = curve->_params().words();
27,068,502✔
617

618
         StorageUnit t = {};
27,068,502✔
619
         W carry = bigint_add3_nc(t.data(), a.data(), words, b.data(), words);
54,137,004✔
620

621
         StorageUnit r = {};
27,068,502✔
622
         bigint_monty_maybe_sub(words, r.data(), carry, t.data(), curve->_params().field().data());
27,068,502✔
623
         return GenericField(curve, r);
27,068,502✔
624
      }
625

626
      friend GenericField operator-(const GenericField& a, const GenericField& b) { return a + b.negate(); }
20,723,616✔
627

628
      friend GenericField operator*(const GenericField& a, const GenericField& b) {
23,727,594✔
629
         auto curve = check_curve(a, b);
47,455,188✔
630

631
         std::array<W, 2 * N> z;
23,727,594✔
632
         curve->_params().mul(z, a.value(), b.value());
23,727,594✔
633
         return GenericField(curve, redc(curve, z));
23,727,594✔
634
      }
635

636
      GenericField& operator*=(const GenericField& other) {
7,187,410✔
637
         auto curve = check_curve(*this, other);
14,374,820✔
638

639
         std::array<W, 2 * N> z;
7,187,410✔
640
         curve->_params().mul(z, value(), other.value());
7,187,410✔
641
         m_val = redc(curve, z);
7,187,410✔
642
         return (*this);
7,187,410✔
643
      }
644

645
      GenericField square() const {
28,822,330✔
646
         std::array<W, 2 * N> z;
28,822,330✔
647
         m_curve->_params().sqr(z, value());
28,822,330✔
648
         return GenericField(m_curve, redc(m_curve, z));
28,822,330✔
649
      }
650

651
      GenericField pow_vartime(const StorageUnit& exp) const {
35,139✔
652
         auto one = GenericField::one(curve());
35,139✔
653
         auto bits = curve()->_params().field_bits();
35,139✔
654
         auto words = curve()->_params().words();
35,139✔
655
         return impl_pow_vartime(*this, one, bits, std::span{exp}.last(words));
70,278✔
656
      }
657

658
      GenericField negate() const {
20,730,836✔
659
         auto x_is_zero = CT::all_zeros(this->data(), N);
41,461,672✔
660

661
         StorageUnit r;
20,730,836✔
662
         bigint_sub3(r.data(), m_curve->_params().field().data(), N, this->data(), N);
20,730,836✔
663
         x_is_zero.if_set_zero_out(r.data(), N);
20,730,836✔
664
         return GenericField(m_curve, r);
20,730,836✔
665
      }
666

667
      GenericField invert() const { return pow_vartime(m_curve->_params().field_minus_2()); }
32,268✔
668

669
      template <concepts::resizable_byte_buffer T>
670
      T serialize() const {
3,646✔
671
         T bytes(m_curve->_params().field_bytes());
3,646✔
672
         serialize_to(bytes);
3,646✔
673
         return bytes;
3,646✔
674
      }
×
675

676
      void serialize_to(std::span<uint8_t> bytes) const {
55,210✔
677
         auto v = from_rep(m_curve, m_val);
55,210✔
678
         std::reverse(v.begin(), v.end());
55,210✔
679

680
         const size_t flen = m_curve->_params().field_bytes();
55,210✔
681
         BOTAN_ARG_CHECK(bytes.size() == flen, "Expected output span provided");
55,210✔
682

683
         // Remove leading zero bytes
684
         const auto padded_bytes = store_be(v);
55,210✔
685
         const size_t extra = N * WordInfo<W>::bytes - flen;
55,210✔
686
         copy_mem(bytes, std::span{padded_bytes}.subspan(extra, flen));
55,210✔
687
      }
55,210✔
688

689
      CT::Choice is_zero() const { return CT::all_zeros(m_val.data(), m_curve->_params().words()).as_choice(); }
8,377,278✔
690

691
      CT::Choice is_nonzero() const { return !is_zero(); }
51,172✔
692

693
      CT::Choice operator==(const GenericField& other) const {
24,225✔
694
         if(this->m_curve != other.m_curve) {
24,225✔
695
            return CT::Choice::no();
×
696
         }
697

698
         return CT::is_equal(m_val.data(), other.m_val.data(), m_curve->_params().words()).as_choice();
24,225✔
699
      }
700

701
      const StorageUnit& stash_value() const { return m_val; }
702

703
      const GenericPrimeOrderCurve* curve() const { return m_curve; }
35,139✔
704

705
      CT::Choice is_even() const {
2,871✔
706
         auto v = from_rep(m_curve, m_val);
2,871✔
707
         return !CT::Choice::from_int(v[0] & 0x01);
2,871✔
708
      }
709

710
      /**
711
      * Convert the integer to standard representation and return the sequence of words
712
      */
713
      StorageUnit to_words() const { return from_rep(m_curve, m_val); }
2,207✔
714

715
      void _const_time_poison() const { CT::poison(m_val); }
12,860✔
716

717
      void _const_time_unpoison() const { CT::unpoison(m_val); }
12,860✔
718

719
      static void conditional_swap(CT::Choice cond, GenericField& x, GenericField& y) {
25,228✔
720
         const W mask = CT::Mask<W>::from_choice(cond).value();
25,228✔
721

722
         for(size_t i = 0; i != N; ++i) {
252,280✔
723
            auto nx = choose(mask, y.m_val[i], x.m_val[i]);
227,052✔
724
            auto ny = choose(mask, x.m_val[i], y.m_val[i]);
227,052✔
725
            x.m_val[i] = nx;
227,052✔
726
            y.m_val[i] = ny;
227,052✔
727
         }
728
      }
25,228✔
729

730
      void conditional_assign(CT::Choice cond, const GenericField& nx) {
5,742✔
731
         const W mask = CT::Mask<W>::from_choice(cond).value();
5,742✔
732

733
         for(size_t i = 0; i != N; ++i) {
57,420✔
734
            m_val[i] = choose(mask, nx.m_val[i], m_val[i]);
51,678✔
735
         }
736
      }
5,742✔
737

738
      /**
739
      * Conditional assignment
740
      *
741
      * If `cond` is true, sets `x` to `nx` and `y` to `ny`
742
      */
743
      static void conditional_assign(
23,376,092✔
744
         GenericField& x, GenericField& y, CT::Choice cond, const GenericField& nx, const GenericField& ny) {
745
         const W mask = CT::Mask<W>::from_choice(cond).value();
23,376,092✔
746

747
         for(size_t i = 0; i != N; ++i) {
233,760,920✔
748
            x.m_val[i] = choose(mask, nx.m_val[i], x.m_val[i]);
210,384,828✔
749
            y.m_val[i] = choose(mask, ny.m_val[i], y.m_val[i]);
210,384,828✔
750
         }
751
      }
23,376,092✔
752

753
      /**
754
      * Conditional assignment
755
      *
756
      * If `cond` is true, sets `x` to `nx`, `y` to `ny`, and `z` to `nz`
757
      */
758
      static void conditional_assign(GenericField& x,
3,136,896✔
759
                                     GenericField& y,
760
                                     GenericField& z,
761
                                     CT::Choice cond,
762
                                     const GenericField& nx,
763
                                     const GenericField& ny,
764
                                     const GenericField& nz) {
765
         const W mask = CT::Mask<W>::from_choice(cond).value();
3,136,896✔
766

767
         for(size_t i = 0; i != N; ++i) {
31,368,960✔
768
            x.m_val[i] = choose(mask, nx.m_val[i], x.m_val[i]);
28,232,064✔
769
            y.m_val[i] = choose(mask, ny.m_val[i], y.m_val[i]);
28,232,064✔
770
            z.m_val[i] = choose(mask, nz.m_val[i], z.m_val[i]);
28,232,064✔
771
         }
772
      }
3,136,896✔
773

774
      std::pair<GenericField, CT::Choice> sqrt() const {
2,871✔
775
         BOTAN_STATE_CHECK(m_curve->_params().field()[0] % 4 == 3);
2,871✔
776

777
         auto z = pow_vartime(m_curve->_params().field_p_plus_1_over_4());
2,871✔
778
         const CT::Choice correct = (z.square() == *this);
2,871✔
779
         // Zero out the return value if it would otherwise be incorrect
780
         z.conditional_assign(!correct, zero(m_curve));
5,742✔
781
         return {z, correct};
2,871✔
782
      }
783

784
      GenericField(const GenericPrimeOrderCurve* curve, StorageUnit val) : m_curve(curve), m_val(val) {}
1,440,349✔
785

786
   private:
787
      const StorageUnit& value() const { return m_val; }
59,737,334✔
788

789
      const W* data() const { return m_val.data(); }
68,530,174✔
790

791
      static const GenericPrimeOrderCurve* check_curve(const GenericField& a, const GenericField& b) {
57,983,506✔
792
         BOTAN_STATE_CHECK(a.m_curve == b.m_curve);
57,983,506✔
793
         return a.m_curve;
57,983,506✔
794
      }
795

796
      static StorageUnit redc(const GenericPrimeOrderCurve* curve, std::array<W, 2 * N> z) {
59,871,054✔
797
         const auto& mod = curve->_params().field();
59,871,054✔
798
         const size_t words = curve->_params().words();
59,871,054✔
799
         StorageUnit r = {};
59,871,054✔
800
         StorageUnit ws = {};
59,871,054✔
801
         bigint_monty_redc(
59,871,054✔
802
            r.data(), z.data(), mod.data(), words, curve->_params().field_p_dash(), ws.data(), ws.size());
59,871,054✔
803
         return r;
59,871,054✔
804
      }
805

806
      static StorageUnit from_rep(const GenericPrimeOrderCurve* curve, StorageUnit z) {
62,495✔
807
         std::array<W, 2 * N> ze = {};
62,495✔
808
         copy_mem(std::span{ze}.template first<N>(), z);
62,495✔
809
         return redc(curve, ze);
62,495✔
810
      }
811

812
      static StorageUnit to_rep(const GenericPrimeOrderCurve* curve, StorageUnit x) {
71,225✔
813
         std::array<W, 2 * N> z;
71,225✔
814
         curve->_params().mul(z, x, curve->_params().field_monty_r2());
71,225✔
815
         return redc(curve, z);
71,225✔
816
      }
817

818
      const GenericPrimeOrderCurve* m_curve;
819
      StorageUnit m_val;
820
};
821

822
/**
823
* Affine Curve Point
824
*
825
* This contains a pair of integers (x,y) which satisfy the curve equation
826
*/
827
class GenericAffinePoint final {
828
   public:
829
      GenericAffinePoint(const GenericField& x, const GenericField& y) : m_x(x), m_y(y) {}
485,068✔
830

831
      GenericAffinePoint(const GenericPrimeOrderCurve* curve) :
832
            m_x(GenericField::zero(curve)), m_y(GenericField::zero(curve)) {}
833

834
      static GenericAffinePoint identity(const GenericPrimeOrderCurve* curve) {
917,908✔
835
         return GenericAffinePoint(GenericField::zero(curve), GenericField::zero(curve));
917,908✔
836
      }
837

838
      static GenericAffinePoint identity(const GenericAffinePoint& pt) { return identity(pt.curve()); }
481,823✔
839

840
      CT::Choice is_identity() const { return x().is_zero() && y().is_zero(); }
1,471,030✔
841

842
      GenericAffinePoint negate() const { return GenericAffinePoint(x(), y().negate()); }
4,284✔
843

844
      /**
845
      * Serialize the point in uncompressed format
846
      */
847
      void serialize_to(std::span<uint8_t> bytes) const {
25,782✔
848
         const size_t fe_bytes = curve()->_params().field_bytes();
25,782✔
849
         BOTAN_ARG_CHECK(bytes.size() == 1 + 2 * fe_bytes, "Buffer size incorrect");
25,782✔
850
         BOTAN_STATE_CHECK(this->is_identity().as_bool() == false);
25,782✔
851
         BufferStuffer pack(bytes);
25,782✔
852
         pack.append(0x04);
25,782✔
853
         x().serialize_to(pack.next(fe_bytes));
25,782✔
854
         y().serialize_to(pack.next(fe_bytes));
25,782✔
855
         BOTAN_DEBUG_ASSERT(pack.full());
25,782✔
856
      }
25,782✔
857

858
      /**
859
      * If idx is zero then return the identity element. Otherwise return pts[idx - 1]
860
      *
861
      * Returns the identity element also if idx is out of range
862
      */
863
      static auto ct_select(std::span<const GenericAffinePoint> pts, size_t idx) {
435,941✔
864
         BOTAN_ARG_CHECK(!pts.empty(), "Cannot select from an empty set");
435,941✔
865
         auto result = GenericAffinePoint::identity(pts[0].curve());
435,941✔
866

867
         // Intentionally wrapping; set to maximum size_t if idx == 0
868
         const size_t idx1 = static_cast<size_t>(idx - 1);
435,941✔
869
         for(size_t i = 0; i != pts.size(); ++i) {
13,950,112✔
870
            const auto found = CT::Mask<size_t>::is_equal(idx1, i).as_choice();
13,514,171✔
871
            result.conditional_assign(found, pts[i]);
13,514,171✔
872
         }
873

874
         return result;
435,941✔
875
      }
876

877
      /**
878
      * Return (x^3 + A*x + B) mod p
879
      */
880
      static GenericField x3_ax_b(const GenericField& x) {
20,231✔
881
         return (x.square() + GenericField::curve_a(x.curve())) * x + GenericField::curve_b(x.curve());
20,231✔
882
      }
883

884
      /**
885
      * Point deserialization
886
      *
887
      * This accepts compressed or uncompressed formats.
888
      */
889
      static std::optional<GenericAffinePoint> deserialize(const GenericPrimeOrderCurve* curve,
8,645✔
890
                                                           std::span<const uint8_t> bytes) {
891
         const size_t fe_bytes = curve->_params().field_bytes();
8,645✔
892

893
         if(bytes.size() == 1 + 2 * fe_bytes && bytes[0] == 0x04) {
8,645✔
894
            auto x = GenericField::deserialize(curve, bytes.subspan(1, fe_bytes));
5,494✔
895
            auto y = GenericField::deserialize(curve, bytes.subspan(1 + fe_bytes, fe_bytes));
5,494✔
896

897
            if(x && y) {
5,494✔
898
               const auto lhs = (*y).square();
5,494✔
899
               const auto rhs = GenericAffinePoint::x3_ax_b(*x);
5,494✔
900
               if((lhs == rhs).as_bool()) {
5,494✔
901
                  return GenericAffinePoint(*x, *y);
5,429✔
902
               }
903
            }
904
         } else if(bytes.size() == 1 + fe_bytes && (bytes[0] == 0x02 || bytes[0] == 0x03)) {
3,151✔
905
            const CT::Choice y_is_even = CT::Mask<uint8_t>::is_equal(bytes[0], 0x02).as_choice();
2,871✔
906

907
            if(auto x = GenericField::deserialize(curve, bytes.subspan(1, fe_bytes))) {
2,871✔
908
               auto [y, is_square] = x3_ax_b(*x).sqrt();
2,871✔
909

910
               if(is_square.as_bool()) {
2,871✔
911
                  const auto flip_y = y_is_even != y.is_even();
2,871✔
912
                  y.conditional_assign(flip_y, y.negate());
2,871✔
913
                  return GenericAffinePoint(*x, y);
2,871✔
914
               }
915
            }
916
         } else if(bytes.size() == 1 && bytes[0] == 0x00) {
280✔
917
            // See SEC1 section 2.3.4
918
            return GenericAffinePoint::identity(curve);
144✔
919
         }
920

921
         return {};
201✔
922
      }
923

924
      /**
925
      * Return the affine x coordinate
926
      */
927
      const GenericField& x() const { return m_x; }
1,407,890✔
928

929
      /**
930
      * Return the affine y coordinate
931
      */
932
      const GenericField& y() const { return m_y; }
1,410,032✔
933

934
      /**
935
      * Conditional assignment of an affine point
936
      */
937
      void conditional_assign(CT::Choice cond, const GenericAffinePoint& pt) {
23,376,092✔
938
         GenericField::conditional_assign(m_x, m_y, cond, pt.x(), pt.y());
23,376,092✔
939
      }
940

941
      const GenericPrimeOrderCurve* curve() const { return m_x.curve(); }
943,546✔
942

943
      void _const_time_poison() const { CT::poison_all(m_x, m_y); }
944

945
      void _const_time_unpoison() const { CT::unpoison_all(m_x, m_y); }
946

947
   private:
948
      GenericField m_x;
949
      GenericField m_y;
950
};
951

952
class GenericProjectivePoint final {
953
   public:
954
      typedef GenericProjectivePoint Self;
955

956
      using FieldElement = GenericField;
957

958
      /**
959
      * Convert a point from affine to projective form
960
      */
961
      static Self from_affine(const GenericAffinePoint& pt) {
25,228✔
962
         auto x = pt.x();
25,228✔
963
         auto y = pt.y();
25,228✔
964
         auto z = GenericField::one(x.curve());
25,228✔
965

966
         // If pt is identity (0,0) swap y/z to convert (0,0,1) into (0,1,0)
967
         GenericField::conditional_swap(pt.is_identity(), y, z);
25,228✔
968
         return GenericProjectivePoint(x, y, z);
25,228✔
969
      }
970

971
      /**
972
      * Return the identity element
973
      */
974
      static Self identity(const GenericPrimeOrderCurve* curve) {
975
         return Self(GenericField::zero(curve), GenericField::one(curve), GenericField::zero(curve));
976
      }
977

978
      /**
979
      * Default constructor: the identity element
980
      */
981
      GenericProjectivePoint(const GenericPrimeOrderCurve* curve) :
4,768✔
982
            m_x(GenericField::zero(curve)), m_y(GenericField::one(curve)), m_z(GenericField::zero(curve)) {}
4,768✔
983

984
      /**
985
      * Affine constructor: take x/y coordinates
986
      */
987
      GenericProjectivePoint(const GenericField& x, const GenericField& y) :
988
            m_x(x), m_y(y), m_z(GenericField::one(m_x.curve())) {}
989

990
      /**
991
      * Projective constructor: take x/y/z coordinates
992
      */
993
      GenericProjectivePoint(const GenericField& x, const GenericField& y, const GenericField& z) :
2,680,676✔
994
            m_x(x), m_y(y), m_z(z) {}
2,643,582✔
995

996
      friend Self operator+(const Self& a, const Self& b) { return Self::add(a, b); }
186,681✔
997

998
      friend Self operator+(const Self& a, const GenericAffinePoint& b) { return Self::add_mixed(a, b); }
52,841✔
999

1000
      friend Self operator+(const GenericAffinePoint& a, const Self& b) { return Self::add_mixed(b, a); }
30,784✔
1001

1002
      Self& operator+=(const Self& other) {
1003
         (*this) = (*this) + other;
1004
         return (*this);
1005
      }
1006

1007
      Self& operator+=(const GenericAffinePoint& other) {
1,296,515✔
1008
         (*this) = (*this) + other;
1,296,515✔
1009
         return (*this);
1,296,515✔
1010
      }
1011

1012
      CT::Choice is_identity() const { return z().is_zero(); }
2,059,787✔
1013

1014
      /**
1015
      * Mixed (projective + affine) point addition
1016
      */
1017
      static Self add_mixed(const Self& a, const GenericAffinePoint& b) {
1,382,108✔
1018
         return point_add_mixed<Self, GenericAffinePoint, GenericField>(a, b, GenericField::one(a.curve()));
2,764,216✔
1019
      }
1020

1021
      /**
1022
      * Projective point addition
1023
      */
1024
      static Self add(const Self& a, const Self& b) { return point_add<Self, GenericField>(a, b); }
186,681✔
1025

1026
      /**
1027
      * Iterated point doubling
1028
      */
1029
      Self dbl_n(size_t n) const {
869,712✔
1030
         if(curve()->_params().a_is_minus_3()) {
869,712✔
1031
            return dbl_n_a_minus_3(*this, n);
435,295✔
1032
         } else if(curve()->_params().a_is_zero()) {
434,417✔
1033
            return dbl_n_a_zero(*this, n);
43,813✔
1034
         } else {
1035
            const auto A = GenericField::curve_a(curve());
390,604✔
1036
            return dbl_n_generic(*this, A, n);
390,604✔
1037
         }
1038
      }
1039

1040
      /**
1041
      * Point doubling
1042
      */
1043
      Self dbl() const {
205,422✔
1044
         if(curve()->_params().a_is_minus_3()) {
205,422✔
1045
            return dbl_a_minus_3(*this);
86,622✔
1046
         } else if(curve()->_params().a_is_zero()) {
118,800✔
1047
            return dbl_a_zero(*this);
65,171✔
1048
         } else {
1049
            const auto A = GenericField::curve_a(curve());
53,629✔
1050
            return dbl_generic(*this, A);
53,629✔
1051
         }
1052
      }
1053

1054
      /**
1055
      * Point negation
1056
      */
1057
      Self negate() const { return Self(x(), y().negate(), z()); }
1058

1059
      /**
1060
      * Randomize the point representation
1061
      *
1062
      * Projective coordinates are redundant; if (x,y,z) is a projective
1063
      * point then so is (x*r^2,y*r^3,z*r) for any non-zero r.
1064
      */
1065
      void randomize_rep(RandomNumberGenerator& rng) {
51,440✔
1066
         // In certain contexts we may be called with a Null_RNG; in that case the
1067
         // caller is accepting that randomization will not occur
1068

1069
         if(rng.is_seeded()) {
51,440✔
1070
            auto r = GenericField::random(curve(), rng);
51,172✔
1071

1072
            auto r2 = r.square();
51,172✔
1073
            auto r3 = r2 * r;
51,172✔
1074

1075
            m_x *= r2;
51,172✔
1076
            m_y *= r3;
51,172✔
1077
            m_z *= r;
51,172✔
1078
         }
1079
      }
51,440✔
1080

1081
      /**
1082
      * Return the projective x coordinate
1083
      */
1084
      const GenericField& x() const { return m_x; }
2,275,365✔
1085

1086
      /**
1087
      * Return the projective y coordinate
1088
      */
1089
      const GenericField& y() const { return m_y; }
3,328,112✔
1090

1091
      /**
1092
      * Return the projective z coordinate
1093
      */
1094
      const GenericField& z() const { return m_z; }
3,229,893✔
1095

1096
      const GenericPrimeOrderCurve* curve() const { return m_x.curve(); }
2,508,414✔
1097

1098
      void _const_time_poison() const { CT::poison_all(m_x, m_y, m_z); }
12,860✔
1099

1100
      void _const_time_unpoison() const { CT::unpoison_all(m_x, m_y, m_z); }
12,860✔
1101

1102
   private:
1103
      GenericField m_x;
1104
      GenericField m_y;
1105
      GenericField m_z;
1106
};
1107

1108
class GenericCurve final {
1109
   public:
1110
      typedef GenericField FieldElement;
1111
      typedef GenericScalar Scalar;
1112
      typedef GenericAffinePoint AffinePoint;
1113
      typedef GenericProjectivePoint ProjectivePoint;
1114

1115
      typedef word WordType;
1116
      static constexpr size_t Words = PCurve::PrimeOrderCurve::StorageWords;
1117
};
1118

1119
class GenericBlindedScalarBits final {
6,107✔
1120
   public:
1121
      GenericBlindedScalarBits(const GenericScalar& scalar, RandomNumberGenerator& rng, size_t wb) {
13,448✔
1122
         // Just a simplifying assumption for get_window, can extend to 1..7 as required
1123
         BOTAN_ASSERT_NOMSG(wb == 3 || wb == 4 || wb == 5);
13,448✔
1124

1125
         const auto& params = scalar.curve()->_params();
13,448✔
1126

1127
         const size_t order_bits = params.order_bits();
13,448✔
1128
         const size_t blinder_bits = blinding_bits(order_bits);
26,896✔
1129

1130
         const size_t mask_words = blinder_bits / WordInfo<word>::bits;
13,448✔
1131
         const size_t mask_bytes = mask_words * WordInfo<word>::bytes;
13,448✔
1132

1133
         const size_t words = params.words();
13,448✔
1134

1135
         secure_vector<uint8_t> maskb(mask_bytes);
26,896✔
1136
         if(rng.is_seeded()) {
13,448✔
1137
            rng.randomize(maskb);
13,381✔
1138
         } else {
1139
            auto sbytes = scalar.serialize<std::vector<uint8_t>>();
67✔
1140
            for(size_t i = 0; i != sbytes.size(); ++i) {
1,745✔
1141
               maskb[i % mask_bytes] ^= sbytes[i];
1,678✔
1142
            }
1143
         }
67✔
1144

1145
         std::array<word, PrimeOrderCurve::StorageWords> mask = {};
13,448✔
1146
         load_le(mask.data(), maskb.data(), mask_words);
13,448✔
1147
         mask[mask_words - 1] |= WordInfo<word>::top_bit;
13,448✔
1148
         mask[0] |= 1;
13,448✔
1149

1150
         std::array<word, 2 * PrimeOrderCurve::StorageWords> mask_n = {};
13,448✔
1151

1152
         const auto sw = scalar.to_words();
13,448✔
1153

1154
         // Compute masked scalar s + k*n
1155
         params.mul(mask_n, mask, params.order());
13,448✔
1156
         bigint_add2_nc(mask_n.data(), 2 * words, sw.data(), words);
13,448✔
1157

1158
         std::reverse(mask_n.begin(), mask_n.end());
13,448✔
1159
         m_bytes = store_be<std::vector<uint8_t>>(mask_n);
13,448✔
1160
         m_bits = order_bits + blinder_bits;
13,448✔
1161
         m_window_bits = wb;
13,448✔
1162
         m_windows = (order_bits + blinder_bits + wb - 1) / wb;
13,448✔
1163
      }
13,448✔
1164

1165
      size_t windows() const { return m_windows; }
1166

1167
      size_t bits() const { return m_bits; }
12,860✔
1168

1169
      size_t get_window(size_t offset) const {
972,651✔
1170
         if(m_window_bits == 3) {
972,651✔
1171
            return read_window_bits<3>(std::span{m_bytes}, offset);
109,774✔
1172
         } else if(m_window_bits == 4) {
862,877✔
1173
            return read_window_bits<4>(std::span{m_bytes}, offset);
426,936✔
1174
         } else if(m_window_bits == 5) {
435,941✔
1175
            return read_window_bits<5>(std::span{m_bytes}, offset);
435,941✔
1176
         } else {
1177
            BOTAN_ASSERT_UNREACHABLE();
×
1178
         }
1179
      }
1180

1181
      static size_t blinding_bits(size_t order_bits) {
13,448✔
1182
         if(order_bits > 512) {
13,593✔
1183
            return blinding_bits(512);
1184
         }
1185

1186
         const size_t wb = sizeof(word) * 8;
13,593✔
1187
         return ((order_bits / 4 + wb - 1) / wb) * wb;
13,448✔
1188
      }
1189

1190
   private:
1191
      std::vector<uint8_t> m_bytes;
1192
      size_t m_bits;
1193
      size_t m_windows;
1194
      size_t m_window_bits;
1195
};
1196

1197
class GenericWindowedMul final {
11,038✔
1198
   public:
1199
      static constexpr size_t WindowBits = VarPointWindowBits;
1200
      static constexpr size_t TableSize = (1 << WindowBits) - 1;
1201

1202
      GenericWindowedMul(const GenericAffinePoint& pt) : m_table(varpoint_setup<GenericCurve, TableSize>(pt)) {}
5,519✔
1203

1204
      GenericProjectivePoint mul(const GenericScalar& s, RandomNumberGenerator& rng) {
5,519✔
1205
         GenericBlindedScalarBits bits(s, rng, WindowBits);
5,519✔
1206

1207
         return varpoint_exec<GenericCurve, WindowBits>(m_table, bits, rng);
5,519✔
1208
      }
5,519✔
1209

1210
   private:
1211
      AffinePointTable<GenericCurve> m_table;
1212
};
1213

1214
class GenericBaseMulTable final {
290✔
1215
   public:
1216
      static constexpr size_t WindowBits = BasePointWindowBits;
1217

1218
      static constexpr size_t WindowElements = (1 << WindowBits) - 1;
1219

1220
      GenericBaseMulTable(const GenericAffinePoint& pt) :
145✔
1221
            m_table(basemul_setup<GenericCurve, WindowBits>(pt, blinded_scalar_bits(*pt.curve()))) {}
435✔
1222

1223
      GenericProjectivePoint mul(const GenericScalar& s, RandomNumberGenerator& rng) {
6,753✔
1224
         GenericBlindedScalarBits scalar(s, rng, WindowBits);
6,753✔
1225
         return basemul_exec<GenericCurve, WindowBits>(m_table, scalar, rng);
6,753✔
1226
      }
6,753✔
1227

1228
   private:
1229
      static size_t blinded_scalar_bits(const GenericPrimeOrderCurve& curve) {
145✔
1230
         const size_t order_bits = curve.order_bits();
145✔
1231
         return order_bits + GenericBlindedScalarBits::blinding_bits(order_bits);
290✔
1232
      }
1233

1234
      std::vector<GenericAffinePoint> m_table;
1235
};
1236

1237
class GenericWindowedMul2 final {
1238
   public:
1239
      static constexpr size_t WindowBits = Mul2PrecompWindowBits;
1240

1241
      GenericWindowedMul2(const GenericWindowedMul2& other) = delete;
1242
      GenericWindowedMul2(GenericWindowedMul2&& other) = delete;
1243
      GenericWindowedMul2& operator=(const GenericWindowedMul2& other) = delete;
1244
      GenericWindowedMul2& operator=(GenericWindowedMul2&& other) = delete;
1245

1246
      ~GenericWindowedMul2() = default;
588✔
1247

1248
      GenericWindowedMul2(const GenericAffinePoint& p, const GenericAffinePoint& q) :
588✔
1249
            m_table(mul2_setup<GenericCurve, WindowBits>(p, q)) {}
1,176✔
1250

1251
      GenericProjectivePoint mul2(const GenericScalar& x, const GenericScalar& y, RandomNumberGenerator& rng) const {
588✔
1252
         GenericBlindedScalarBits x_bits(x, rng, WindowBits);
588✔
1253
         GenericBlindedScalarBits y_bits(y, rng, WindowBits);
588✔
1254
         return mul2_exec<GenericCurve, WindowBits>(m_table, x_bits, y_bits, rng);
588✔
1255
      }
1,176✔
1256

1257
   private:
1258
      AffinePointTable<GenericCurve> m_table;
1259
};
1260

1261
class GenericVartimeWindowedMul2 final : public PrimeOrderCurve::PrecomputedMul2Table {
1262
   public:
1263
      static constexpr size_t WindowBits = Mul2PrecompWindowBits;
1264

1265
      GenericVartimeWindowedMul2(const GenericVartimeWindowedMul2& other) = delete;
1266
      GenericVartimeWindowedMul2(GenericVartimeWindowedMul2&& other) = delete;
1267
      GenericVartimeWindowedMul2& operator=(const GenericVartimeWindowedMul2& other) = delete;
1268
      GenericVartimeWindowedMul2& operator=(GenericVartimeWindowedMul2&& other) = delete;
1269

1270
      ~GenericVartimeWindowedMul2() override = default;
3,560✔
1271

1272
      GenericVartimeWindowedMul2(const GenericAffinePoint& p, const GenericAffinePoint& q) :
1,780✔
1273
            m_table(to_affine_batch<GenericCurve>(mul2_setup<GenericCurve, WindowBits>(p, q))) {}
3,560✔
1274

1275
      GenericProjectivePoint mul2_vartime(const GenericScalar& x, const GenericScalar& y) const {
4,768✔
1276
         const auto x_bits = x.serialize<std::vector<uint8_t>>();
4,768✔
1277
         const auto y_bits = y.serialize<std::vector<uint8_t>>();
4,768✔
1278

1279
         const auto& curve = m_table[0].curve();
4,768✔
1280
         auto accum = GenericProjectivePoint(curve);
4,768✔
1281

1282
         const size_t order_bits = curve->order_bits();
4,768✔
1283

1284
         const size_t windows = (order_bits + WindowBits - 1) / WindowBits;
4,768✔
1285

1286
         for(size_t i = 0; i != windows; ++i) {
403,532✔
1287
            auto x_i = read_window_bits<WindowBits>(std::span{x_bits}, (windows - i - 1) * WindowBits);
398,764✔
1288
            auto y_i = read_window_bits<WindowBits>(std::span{y_bits}, (windows - i - 1) * WindowBits);
398,764✔
1289

1290
            if(i > 0) {
398,764✔
1291
               accum = accum.dbl_n(WindowBits);
393,996✔
1292
            }
1293

1294
            const size_t idx = (y_i << WindowBits) + x_i;
398,764✔
1295

1296
            if(idx > 0) {
398,764✔
1297
               accum += m_table[idx - 1];
391,611✔
1298
            }
1299
         }
1300

1301
         return accum;
4,768✔
1302
      }
9,536✔
1303

1304
   private:
1305
      std::vector<GenericAffinePoint> m_table;
1306
};
1307

1308
GenericPrimeOrderCurve::GenericPrimeOrderCurve(
145✔
1309
   const BigInt& p, const BigInt& a, const BigInt& b, const BigInt& base_x, const BigInt& base_y, const BigInt& order) :
145✔
1310
      m_params(std::make_unique<GenericCurveParams>(p, a, b, base_x, base_y, order)) {}
145✔
1311

1312
void GenericPrimeOrderCurve::_precompute_base_mul() {
145✔
1313
   BOTAN_STATE_CHECK(m_basemul == nullptr);
145✔
1314
   m_basemul = std::make_unique<GenericBaseMulTable>(from_stash(generator()));
145✔
1315
}
145✔
1316

1317
size_t GenericPrimeOrderCurve::order_bits() const {
4,913✔
1318
   return _params().order_bits();
4,913✔
1319
}
1320

1321
size_t GenericPrimeOrderCurve::scalar_bytes() const {
×
1322
   return _params().order_bytes();
×
1323
}
1324

1325
size_t GenericPrimeOrderCurve::field_element_bytes() const {
60,532✔
1326
   return _params().field_bytes();
60,532✔
1327
}
1328

1329
PrimeOrderCurve::ProjectivePoint GenericPrimeOrderCurve::mul_by_g(const Scalar& scalar,
5,531✔
1330
                                                                  RandomNumberGenerator& rng) const {
1331
   BOTAN_STATE_CHECK(m_basemul != nullptr);
5,531✔
1332
   return stash(m_basemul->mul(from_stash(scalar), rng));
5,531✔
1333
}
1334

1335
PrimeOrderCurve::Scalar GenericPrimeOrderCurve::base_point_mul_x_mod_order(const Scalar& scalar,
1,222✔
1336
                                                                           RandomNumberGenerator& rng) const {
1337
   BOTAN_STATE_CHECK(m_basemul != nullptr);
1,222✔
1338
   auto pt_s = m_basemul->mul(from_stash(scalar), rng);
1,222✔
1339
   const auto x_bytes = to_affine_x<GenericCurve>(pt_s).serialize<secure_vector<uint8_t>>();
1,222✔
1340
   return stash(GenericScalar::from_wide_bytes(this, x_bytes).value());
2,444✔
1341
}
1,222✔
1342

1343
PrimeOrderCurve::ProjectivePoint GenericPrimeOrderCurve::mul(const AffinePoint& pt,
3,095✔
1344
                                                             const Scalar& scalar,
1345
                                                             RandomNumberGenerator& rng) const {
1346
   GenericWindowedMul pt_table(from_stash(pt));
3,095✔
1347
   return stash(pt_table.mul(from_stash(scalar), rng));
3,095✔
1348
}
3,095✔
1349

1350
secure_vector<uint8_t> GenericPrimeOrderCurve::mul_x_only(const AffinePoint& pt,
2,424✔
1351
                                                          const Scalar& scalar,
1352
                                                          RandomNumberGenerator& rng) const {
1353
   GenericWindowedMul pt_table(from_stash(pt));
2,424✔
1354
   auto pt_s = pt_table.mul(from_stash(scalar), rng);
2,424✔
1355
   return to_affine_x<GenericCurve>(pt_s).serialize<secure_vector<uint8_t>>();
2,424✔
1356
}
2,424✔
1357

1358
std::unique_ptr<const PrimeOrderCurve::PrecomputedMul2Table> GenericPrimeOrderCurve::mul2_setup_g(
1,780✔
1359
   const AffinePoint& q) const {
1360
   return std::make_unique<GenericVartimeWindowedMul2>(from_stash(generator()), from_stash(q));
3,560✔
1361
}
1362

1363
std::optional<PrimeOrderCurve::ProjectivePoint> GenericPrimeOrderCurve::mul2_vartime(const PrecomputedMul2Table& tableb,
768✔
1364
                                                                                     const Scalar& s1,
1365
                                                                                     const Scalar& s2) const {
1366
   const auto& tbl = dynamic_cast<const GenericVartimeWindowedMul2&>(tableb);
768✔
1367
   auto pt = tbl.mul2_vartime(from_stash(s1), from_stash(s2));
768✔
1368
   if(pt.is_identity().as_bool()) {
768✔
1369
      return {};
×
1370
   } else {
1371
      return stash(pt);
768✔
1372
   }
1373
}
1374

1375
std::optional<PrimeOrderCurve::ProjectivePoint> GenericPrimeOrderCurve::mul_px_qy(
588✔
1376
   const AffinePoint& p, const Scalar& x, const AffinePoint& q, const Scalar& y, RandomNumberGenerator& rng) const {
1377
   GenericWindowedMul2 table(from_stash(p), from_stash(q));
588✔
1378
   auto pt = table.mul2(from_stash(x), from_stash(y), rng);
588✔
1379
   if(pt.is_identity().as_bool()) {
588✔
1380
      return {};
84✔
1381
   } else {
1382
      return stash(pt);
504✔
1383
   }
1384
}
588✔
1385

1386
bool GenericPrimeOrderCurve::mul2_vartime_x_mod_order_eq(const PrecomputedMul2Table& tableb,
4,000✔
1387
                                                         const Scalar& v,
1388
                                                         const Scalar& s1,
1389
                                                         const Scalar& s2) const {
1390
   const auto& tbl = dynamic_cast<const GenericVartimeWindowedMul2&>(tableb);
4,000✔
1391
   auto pt = tbl.mul2_vartime(from_stash(s1), from_stash(s2));
4,000✔
1392

1393
   if(!pt.is_identity().as_bool()) {
4,000✔
1394
      const auto z2 = pt.z().square();
3,987✔
1395

1396
      const auto v_bytes = from_stash(v).serialize<std::vector<uint8_t>>();
3,987✔
1397

1398
      if(auto fe_v = GenericField::deserialize(this, v_bytes)) {
3,987✔
1399
         if((*fe_v * z2 == pt.x()).as_bool()) {
3,987✔
1400
            return true;
1,614✔
1401
         }
1402

1403
         if(_params().order_is_less_than_field()) {
2,380✔
1404
            const auto n = GenericField::from_words(this, _params().order());
2,207✔
1405
            const auto neg_n = n.negate().to_words();
2,207✔
1406

1407
            const auto vw = fe_v->to_words();
2,207✔
1408
            if(bigint_ct_is_lt(vw.data(), vw.size(), neg_n.data(), neg_n.size()).as_bool()) {
2,207✔
1409
               return (((*fe_v + n) * z2) == pt.x()).as_bool();
7✔
1410
            }
1411
         }
1412
      }
1413
   }
3,987✔
1414

1415
   return false;
1416
}
1417

1418
PrimeOrderCurve::AffinePoint GenericPrimeOrderCurve::generator() const {
1,925✔
1419
   return PrimeOrderCurve::AffinePoint::_create(shared_from_this(), _params().base_x(), _params().base_y());
1,925✔
1420
}
1421

1422
PrimeOrderCurve::AffinePoint GenericPrimeOrderCurve::point_to_affine(const ProjectivePoint& pt) const {
11,866✔
1423
   auto affine = to_affine<GenericCurve>(from_stash(pt));
11,866✔
1424

1425
   const auto y2 = affine.y().square();
11,866✔
1426
   const auto x3_ax_b = GenericCurve::AffinePoint::x3_ax_b(affine.x());
11,866✔
1427
   const auto valid_point = affine.is_identity() || (y2 == x3_ax_b);
11,866✔
1428

1429
   BOTAN_ASSERT(valid_point.as_bool(), "Computed point is on the curve");
11,866✔
1430

1431
   return stash(affine);
11,866✔
1432
}
1433

1434
PrimeOrderCurve::ProjectivePoint GenericPrimeOrderCurve::point_add(const AffinePoint& a, const AffinePoint& b) const {
1,968✔
1435
   return stash(GenericProjectivePoint::from_affine(from_stash(a)) + from_stash(b));
1,968✔
1436
}
1437

1438
PrimeOrderCurve::AffinePoint GenericPrimeOrderCurve::point_negate(const AffinePoint& pt) const {
2,142✔
1439
   return stash(from_stash(pt).negate());
2,142✔
1440
}
1441

1442
bool GenericPrimeOrderCurve::affine_point_is_identity(const AffinePoint& pt) const {
26,046✔
1443
   return from_stash(pt).is_identity().as_bool();
26,046✔
1444
}
1445

1446
void GenericPrimeOrderCurve::serialize_point(std::span<uint8_t> bytes, const AffinePoint& pt) const {
25,782✔
1447
   from_stash(pt).serialize_to(bytes);
25,782✔
1448
}
25,782✔
1449

1450
void GenericPrimeOrderCurve::serialize_scalar(std::span<uint8_t> bytes, const Scalar& scalar) const {
43,597✔
1451
   BOTAN_ARG_CHECK(bytes.size() == _params().order_bytes(), "Invalid length to serialize_scalar");
43,597✔
1452
   from_stash(scalar).serialize_to(bytes);
43,597✔
1453
}
43,597✔
1454

1455
std::optional<PrimeOrderCurve::Scalar> GenericPrimeOrderCurve::deserialize_scalar(
12,266✔
1456
   std::span<const uint8_t> bytes) const {
1457
   if(auto s = GenericScalar::deserialize(this, bytes)) {
12,266✔
1458
      return stash(s.value());
12,052✔
1459
   } else {
1460
      return {};
214✔
1461
   }
1462
}
1463

1464
std::optional<PrimeOrderCurve::Scalar> GenericPrimeOrderCurve::scalar_from_wide_bytes(
8,418✔
1465
   std::span<const uint8_t> bytes) const {
1466
   if(auto s = GenericScalar::from_wide_bytes(this, bytes)) {
8,418✔
1467
      return stash(s.value());
8,418✔
1468
   } else {
1469
      return {};
×
1470
   }
1471
}
1472

1473
std::optional<PrimeOrderCurve::AffinePoint> GenericPrimeOrderCurve::deserialize_point(
8,645✔
1474
   std::span<const uint8_t> bytes) const {
1475
   if(auto pt = GenericAffinePoint::deserialize(this, bytes)) {
8,645✔
1476
      return stash(pt.value());
8,444✔
1477
   } else {
1478
      return {};
201✔
1479
   }
1480
}
1481

1482
PrimeOrderCurve::Scalar GenericPrimeOrderCurve::scalar_add(const Scalar& a, const Scalar& b) const {
7,734✔
1483
   return stash(from_stash(a) + from_stash(b));
7,734✔
1484
}
1485

1486
PrimeOrderCurve::Scalar GenericPrimeOrderCurve::scalar_sub(const Scalar& a, const Scalar& b) const {
6,289✔
1487
   return stash(from_stash(a) - from_stash(b));
6,289✔
1488
}
1489

1490
PrimeOrderCurve::Scalar GenericPrimeOrderCurve::scalar_mul(const Scalar& a, const Scalar& b) const {
29,970✔
1491
   return stash(from_stash(a) * from_stash(b));
29,970✔
1492
}
1493

1494
PrimeOrderCurve::Scalar GenericPrimeOrderCurve::scalar_square(const Scalar& s) const {
2,328✔
1495
   return stash(from_stash(s).square());
2,328✔
1496
}
1497

1498
PrimeOrderCurve::Scalar GenericPrimeOrderCurve::scalar_invert(const Scalar& s) const {
5,893✔
1499
   return stash(from_stash(s).invert());
11,786✔
1500
}
1501

1502
PrimeOrderCurve::Scalar GenericPrimeOrderCurve::scalar_invert_vartime(const Scalar& s) const {
5,495✔
1503
   // TODO support BEEA for this
1504
   return stash(from_stash(s).invert());
10,990✔
1505
}
1506

1507
PrimeOrderCurve::Scalar GenericPrimeOrderCurve::scalar_negate(const Scalar& s) const {
5,298✔
1508
   return stash(from_stash(s).negate());
5,298✔
1509
}
1510

1511
bool GenericPrimeOrderCurve::scalar_is_zero(const Scalar& s) const {
13,475✔
1512
   return from_stash(s).is_zero().as_bool();
13,475✔
1513
}
1514

1515
bool GenericPrimeOrderCurve::scalar_equal(const Scalar& a, const Scalar& b) const {
1,536✔
1516
   return (from_stash(a) == from_stash(b)).as_bool();
1,536✔
1517
}
1518

1519
PrimeOrderCurve::Scalar GenericPrimeOrderCurve::scalar_one() const {
44✔
1520
   return stash(GenericScalar::one(this));
44✔
1521
}
1522

1523
PrimeOrderCurve::Scalar GenericPrimeOrderCurve::random_scalar(RandomNumberGenerator& rng) const {
18,627✔
1524
   return stash(GenericScalar::random(this, rng));
18,627✔
1525
}
1526

1527
PrimeOrderCurve::Scalar GenericPrimeOrderCurve::stash(const GenericScalar& s) const {
103,370✔
1528
   return Scalar::_create(shared_from_this(), s.stash_value());
103,370✔
1529
}
1530

1531
GenericScalar GenericPrimeOrderCurve::from_stash(const PrimeOrderCurve::Scalar& s) const {
194,115✔
1532
   BOTAN_ARG_CHECK(s._curve().get() == this, "Curve mismatch");
194,115✔
1533
   return GenericScalar(this, s._value());
194,115✔
1534
}
1535

1536
PrimeOrderCurve::AffinePoint GenericPrimeOrderCurve::stash(const GenericAffinePoint& pt) const {
22,452✔
1537
   auto x_w = pt.x().stash_value();
22,452✔
1538
   auto y_w = pt.y().stash_value();
22,452✔
1539
   return AffinePoint::_create(shared_from_this(), x_w, y_w);
22,452✔
1540
}
1541

1542
GenericAffinePoint GenericPrimeOrderCurve::from_stash(const PrimeOrderCurve::AffinePoint& pt) const {
68,306✔
1543
   BOTAN_ARG_CHECK(pt._curve().get() == this, "Curve mismatch");
68,306✔
1544
   auto x = GenericField(this, pt._x());
68,306✔
1545
   auto y = GenericField(this, pt._y());
68,306✔
1546
   return GenericAffinePoint(x, y);
68,306✔
1547
}
1548

1549
PrimeOrderCurve::ProjectivePoint GenericPrimeOrderCurve::stash(const GenericProjectivePoint& pt) const {
11,866✔
1550
   auto x_w = pt.x().stash_value();
11,866✔
1551
   auto y_w = pt.y().stash_value();
11,866✔
1552
   auto z_w = pt.z().stash_value();
11,866✔
1553
   return ProjectivePoint::_create(shared_from_this(), x_w, y_w, z_w);
11,866✔
1554
}
1555

1556
GenericProjectivePoint GenericPrimeOrderCurve::from_stash(const PrimeOrderCurve::ProjectivePoint& pt) const {
11,866✔
1557
   BOTAN_ARG_CHECK(pt._curve().get() == this, "Curve mismatch");
11,866✔
1558
   auto x = GenericField(this, pt._x());
11,866✔
1559
   auto y = GenericField(this, pt._y());
11,866✔
1560
   auto z = GenericField(this, pt._z());
11,866✔
1561
   return GenericProjectivePoint(x, y, z);
11,866✔
1562
}
1563

1564
PrimeOrderCurve::AffinePoint GenericPrimeOrderCurve::hash_to_curve_nu(
×
1565
   std::function<void(std::span<uint8_t>)> expand_message) const {
1566
   BOTAN_UNUSED(expand_message);
×
1567
   throw Not_Implemented("Hash to curve is not implemented for this curve");
×
1568
}
1569

1570
PrimeOrderCurve::ProjectivePoint GenericPrimeOrderCurve::hash_to_curve_ro(
×
1571
   std::function<void(std::span<uint8_t>)> expand_message) const {
1572
   BOTAN_UNUSED(expand_message);
×
1573
   throw Not_Implemented("Hash to curve is not implemented for this curve");
×
1574
}
1575

1576
std::shared_ptr<const PrimeOrderCurve> PCurveInstance::from_params(
244✔
1577
   const BigInt& p, const BigInt& a, const BigInt& b, const BigInt& base_x, const BigInt& base_y, const BigInt& order) {
1578
   // We don't check that p and order are prime here on the assumption this has
1579
   // been checked already by EC_Group
1580

1581
   BOTAN_ARG_CHECK(a >= 0 && a < p, "a is invalid");
488✔
1582
   BOTAN_ARG_CHECK(b > 0 && b < p, "b is invalid");
488✔
1583
   BOTAN_ARG_CHECK(base_x >= 0 && base_x < p, "base_x is invalid");
488✔
1584
   BOTAN_ARG_CHECK(base_y >= 0 && base_y < p, "base_y is invalid");
488✔
1585

1586
   const size_t p_bits = p.bits();
244✔
1587

1588
   // Same size restrictions as EC_Group however here we do not require
1589
   // exactly the primes for the 521 or 239 bit exceptions; this code
1590
   // should work fine with any such prime and we are relying on the higher
1591
   // levels to prevent creating such a group in the first place
1592

1593
   if(p_bits != 521 && p_bits != 239 && (p_bits < 128 || p_bits > 512 || p_bits % 32 != 0)) {
244✔
1594
      return {};
×
1595
   }
1596

1597
   // We don't want to deal with Shanks-Tonelli in the generic case
1598
   if(p % 4 != 3) {
244✔
1599
      return {};
70✔
1600
   }
1601

1602
   // The bit length of the field and order being the same simplifies things
1603
   if(p_bits != order.bits()) {
174✔
1604
      return {};
29✔
1605
   }
1606

1607
   auto gpoc = std::make_shared<GenericPrimeOrderCurve>(p, a, b, base_x, base_y, order);
145✔
1608
   /*
1609
   The implementation of this needs to call shared_from_this which is not usable
1610
   until after the constructor has completed, so we have to do a two-stage
1611
   construction process. This is certainly not so clean but it is contained to
1612
   this single file so seems tolerable.
1613

1614
   Alternately we could lazily compute the base mul table but this brings in
1615
   locking issues which seem a worse alternative overall.
1616
   */
1617
   gpoc->_precompute_base_mul();
145✔
1618
   return gpoc;
145✔
1619
}
145✔
1620

1621
}  // namespace Botan::PCurve
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