Coverage Report

Created: 2024-11-29 06:10

/src/botan/build/include/internal/botan/internal/pcurves.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
* (C) 2024 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6
7
#ifndef BOTAN_PCURVES_H_
8
#define BOTAN_PCURVES_H_
9
10
#include <botan/internal/pcurves_id.h>
11
12
#include <botan/concepts.h>
13
#include <botan/secmem.h>
14
#include <botan/types.h>
15
#include <array>
16
#include <optional>
17
#include <span>
18
#include <string_view>
19
#include <vector>
20
21
namespace Botan {
22
23
class RandomNumberGenerator;
24
25
}  // namespace Botan
26
27
namespace Botan::PCurve {
28
29
/**
30
* An elliptic curve without cofactor in Weierstrass form
31
*/
32
class BOTAN_TEST_API PrimeOrderCurve {
33
   public:
34
      /// Somewhat arbitrary maximum size for a field or scalar
35
      ///
36
      /// Sized to fit at least P-521
37
      static const size_t MaximumBitLength = 521;
38
39
      static const size_t MaximumByteLength = (MaximumBitLength + 7) / 8;
40
41
      /// Number of words used to store MaximumByteLength
42
      static const size_t StorageWords = (MaximumByteLength + sizeof(word) - 1) / sizeof(word);
43
44
0
      static std::shared_ptr<const PrimeOrderCurve> from_name(std::string_view name) {
45
0
         if(auto id = PrimeOrderCurveId::from_string(name)) {
46
0
            return PrimeOrderCurve::from_id(id.value());
47
0
         } else {
48
0
            return {};
49
0
         }
50
0
      }
51
52
      static std::shared_ptr<const PrimeOrderCurve> from_id(PrimeOrderCurveId id);
53
54
      typedef std::array<word, StorageWords> StorageUnit;
55
      typedef std::shared_ptr<const PrimeOrderCurve> CurvePtr;
56
57
      /// Elliptic curve scalar
58
      ///
59
      /// This refers to the set of integers modulo the (prime) group order
60
      /// of the elliptic curve.
61
      class Scalar final {
62
         public:
63
22.3k
            Scalar(const Scalar& other) = default;
64
68.1k
            Scalar(Scalar&& other) = default;
65
0
            Scalar& operator=(const Scalar& other) = default;
66
0
            Scalar& operator=(Scalar&& other) = default;
67
124k
            ~Scalar() = default;
68
69
            /**
70
            * Return the size of the byte encoding of Scalars
71
            */
72
0
            size_t bytes() const { return m_curve->scalar_bytes(); }
73
74
            /**
75
            * Return the fixed length serialization of this scalar
76
            */
77
            template <concepts::resizable_byte_buffer T = std::vector<uint8_t>>
78
            T serialize() const {
79
               T bytes(this->bytes());
80
               m_curve->serialize_scalar(bytes, *this);
81
               return bytes;
82
            }
83
84
            /**
85
            * Perform integer multiplication modulo the group order
86
            */
87
392
            friend Scalar operator*(const Scalar& a, const Scalar& b) { return a.m_curve->scalar_mul(a, b); }
88
89
            /**
90
            * Perform integer addition modulo the group order
91
            */
92
0
            friend Scalar operator+(const Scalar& a, const Scalar& b) { return a.m_curve->scalar_add(a, b); }
93
94
            /**
95
            * Perform integer subtraction modulo the group order
96
            */
97
0
            friend Scalar operator-(const Scalar& a, const Scalar& b) { return a.m_curve->scalar_sub(a, b); }
98
99
            /**
100
            * Check for equality
101
            */
102
0
            friend bool operator==(const Scalar& a, const Scalar& b) { return a.m_curve->scalar_equal(a, b); }
103
104
            /**
105
            * Negate modulo the group order (ie return p - *this where p is the group order)
106
            */
107
0
            Scalar negate() const { return m_curve->scalar_negate(*this); }
108
109
            /**
110
            * Square modulo the group order
111
            */
112
0
            Scalar square() const { return m_curve->scalar_square(*this); }
113
114
            /**
115
            * Return the modular inverse of *this
116
            *
117
            * If *this is zero then returns zero.
118
            */
119
196
            Scalar invert() const { return m_curve->scalar_invert(*this); }
120
121
            /**
122
            * Returns true if this is equal to zero
123
            */
124
392
            bool is_zero() const { return m_curve->scalar_is_zero(*this); }
125
126
45.7k
            const auto& _curve() const { return m_curve; }
127
128
45.7k
            const auto& _value() const { return m_value; }
129
130
33.6k
            static Scalar _create(CurvePtr curve, StorageUnit v) { return Scalar(std::move(curve), v); }
131
132
         private:
133
33.6k
            Scalar(CurvePtr curve, StorageUnit v) : m_curve(std::move(curve)), m_value(v) {}
134
135
            CurvePtr m_curve;
136
            StorageUnit m_value;
137
      };
138
139
      /**
140
      * A point on the elliptic curve in affine form
141
      *
142
      * These points can be serialized, or converted to projective form for computation
143
      */
144
      class AffinePoint final {
145
         public:
146
0
            AffinePoint(const AffinePoint& other) = default;
147
108k
            AffinePoint(AffinePoint&& other) = default;
148
            AffinePoint& operator=(const AffinePoint& other) = default;
149
            AffinePoint& operator=(AffinePoint&& other) = default;
150
155k
            ~AffinePoint() = default;
151
152
0
            static AffinePoint generator(CurvePtr curve) { return curve->generator(); }
153
154
            /**
155
            * Return the size of the uncompressed encoding of points
156
            */
157
46.5k
            size_t bytes() const { return 1 + 2 * m_curve->field_element_bytes(); }
158
159
            /**
160
            * Return the size of the compressed encoding of points
161
            */
162
0
            size_t compressed_bytes() const { return 1 + m_curve->field_element_bytes(); }
163
164
            /**
165
            * Return the serialization of the point in uncompressed form
166
            */
167
            template <concepts::resizable_byte_buffer T = std::vector<uint8_t>>
168
46.5k
            T serialize() const {
169
46.5k
               T bytes(this->bytes());
170
46.5k
               m_curve->serialize_point(bytes, *this);
171
46.5k
               return bytes;
172
46.5k
            }
173
174
            /**
175
            * Return the serialization of the point in compressed form
176
            */
177
            template <concepts::resizable_byte_buffer T = std::vector<uint8_t>>
178
            T serialize_compressed() const {
179
               T bytes(this->compressed_bytes());
180
               m_curve->serialize_point_compressed(bytes, *this);
181
               return bytes;
182
            }
183
184
            /**
185
            * Return the serialization of the x coordinate
186
            */
187
            template <concepts::resizable_byte_buffer T = secure_vector<uint8_t>>
188
            T x_bytes() const {
189
               secure_vector<uint8_t> bytes(m_curve->field_element_bytes());
190
               m_curve->serialize_point_x(bytes, *this);
191
               return bytes;
192
            }
193
194
            /**
195
            * Point negation
196
            */
197
0
            AffinePoint negate() const { return m_curve->point_negate(*this); }
198
199
            /**
200
            * Return true if this is the curve identity element (aka the point at infinity)
201
            */
202
47.2k
            bool is_identity() const { return m_curve->affine_point_is_identity(*this); }
203
204
106k
            const auto& _curve() const { return m_curve; }
205
206
106k
            const auto& _x() const { return m_x; }
207
208
106k
            const auto& _y() const { return m_y; }
209
210
47.2k
            static AffinePoint _create(CurvePtr curve, StorageUnit x, StorageUnit y) {
211
47.2k
               return AffinePoint(std::move(curve), x, y);
212
47.2k
            }
213
214
         private:
215
47.2k
            AffinePoint(CurvePtr curve, StorageUnit x, StorageUnit y) : m_curve(std::move(curve)), m_x(x), m_y(y) {}
216
217
            CurvePtr m_curve;
218
            StorageUnit m_x;
219
            StorageUnit m_y;
220
      };
221
222
      /**
223
      * A point on the elliptic curve in projective form
224
      *
225
      * This is a form that is convenient for computation; it must be converted to
226
      * affine form for comparisons or serialization.
227
      */
228
      class ProjectivePoint final {
229
         public:
230
            ProjectivePoint(const ProjectivePoint& other) = default;
231
0
            ProjectivePoint(ProjectivePoint&& other) = default;
232
            ProjectivePoint& operator=(const ProjectivePoint& other) = default;
233
            ProjectivePoint& operator=(ProjectivePoint&& other) = default;
234
32.5k
            ~ProjectivePoint() = default;
235
236
            /**
237
            * Convert a point from affine to projective form
238
            */
239
0
            static ProjectivePoint from_affine(const AffinePoint& pt) { return pt._curve()->point_to_projective(pt); }
240
241
            /**
242
            * Convert a point from projective to affine form
243
            *
244
            * This operation is expensive; perform it only when required for
245
            * serialization
246
            */
247
32.5k
            AffinePoint to_affine() const { return m_curve->point_to_affine(*this); }
248
249
0
            ProjectivePoint dbl() const { return m_curve->point_double(*this); }
250
251
0
            friend ProjectivePoint operator+(const ProjectivePoint& x, const ProjectivePoint& y) {
252
0
               return x.m_curve->point_add(x, y);
253
0
            }
254
255
0
            friend ProjectivePoint operator+(const ProjectivePoint& x, const AffinePoint& y) {
256
0
               return x.m_curve->point_add_mixed(x, y);
257
0
            }
258
259
32.5k
            const auto& _curve() const { return m_curve; }
260
261
32.5k
            const auto& _x() const { return m_x; }
262
263
32.5k
            const auto& _y() const { return m_y; }
264
265
32.5k
            const auto& _z() const { return m_z; }
266
267
32.5k
            static ProjectivePoint _create(CurvePtr curve, StorageUnit x, StorageUnit y, StorageUnit z) {
268
32.5k
               return ProjectivePoint(std::move(curve), x, y, z);
269
32.5k
            }
270
271
         private:
272
            ProjectivePoint(CurvePtr curve, StorageUnit x, StorageUnit y, StorageUnit z) :
273
32.5k
                  m_curve(std::move(curve)), m_x(x), m_y(y), m_z(z) {}
274
275
            CurvePtr m_curve;
276
            StorageUnit m_x;
277
            StorageUnit m_y;
278
            StorageUnit m_z;
279
      };
280
281
      class PrecomputedMul2Table {
282
         public:
283
330
            virtual ~PrecomputedMul2Table() = default;
284
      };
285
286
38
      virtual ~PrimeOrderCurve() = default;
287
288
      /// Return the bit length of the group order
289
      virtual size_t order_bits() const = 0;
290
291
      /// Return the byte length of the scalar element
292
      virtual size_t scalar_bytes() const = 0;
293
294
      /// Return the byte length of a field element
295
      ///
296
      /// Each point consists of two field elements
297
      virtual size_t field_element_bytes() const = 0;
298
299
      /// Base point multiplication
300
      ///
301
      /// Multiply by the standard generator point g
302
      virtual ProjectivePoint mul_by_g(const Scalar& scalar, RandomNumberGenerator& rng) const = 0;
303
304
      /// Base point multiplication, returning only the x coordinate modulo the group order
305
      ///
306
      /// Multiply by the standard generator point g, then extract the x
307
      /// coordinate as an integer, then reduce the x coordinate modulo the
308
      /// group order
309
      virtual Scalar base_point_mul_x_mod_order(const Scalar& scalar, RandomNumberGenerator& rng) const = 0;
310
311
      /// Generic point multiplication
312
      ///
313
      /// Multiply an arbitrary point by a scalar
314
      virtual ProjectivePoint mul(const AffinePoint& pt, const Scalar& scalar, RandomNumberGenerator& rng) const = 0;
315
316
      /// Setup a table for 2-ary multiplication
317
      virtual std::unique_ptr<const PrecomputedMul2Table> mul2_setup(const AffinePoint& pt1,
318
                                                                     const AffinePoint& pt2) const = 0;
319
320
      /// Perform 2-ary multiplication (variable time)
321
      ///
322
      /// Compute s1*pt1 + s2*pt2 in variable time
323
      ///
324
      /// Returns nullopt if the produced point is the point at infinity
325
      virtual std::optional<ProjectivePoint> mul2_vartime(const PrecomputedMul2Table& table,
326
                                                          const Scalar& s1,
327
                                                          const Scalar& s2) const = 0;
328
329
      /// Perform 2-ary multiplication (constant time)
330
      ///
331
      /// Compute p*x + q*y
332
      ///
333
      /// Returns nullopt if the produced point is the point at infinity
334
      virtual std::optional<ProjectivePoint> mul_px_qy(const AffinePoint& p,
335
                                                       const Scalar& x,
336
                                                       const AffinePoint& q,
337
                                                       const Scalar& y,
338
                                                       RandomNumberGenerator& rng) const = 0;
339
340
      /// Perform 2-ary multiplication (variable time), reducing x modulo order
341
      ///
342
      /// Compute s1*pt1 + s2*pt2 in variable time, then extract the x
343
      /// coordinate of the result, and reduce x modulo the group order. Compare
344
      /// that value with v. If equal, returns true. Otherwise returns false,
345
      /// including if the produced point is the point at infinity
346
      virtual bool mul2_vartime_x_mod_order_eq(const PrecomputedMul2Table& table,
347
                                               const Scalar& v,
348
                                               const Scalar& s1,
349
                                               const Scalar& s2) const = 0;
350
351
      /// Return the standard generator
352
      virtual AffinePoint generator() const = 0;
353
354
      /// Deserialize a point
355
      ///
356
      /// Both compressed and uncompressed encodings are accepted
357
      ///
358
      /// Note that the deprecated "hybrid" encoding is not supported here
359
      virtual std::optional<AffinePoint> deserialize_point(std::span<const uint8_t> bytes) const = 0;
360
361
      /// Deserialize a scalar
362
      ///
363
      /// This function requires the input length be exactly scalar_bytes long;
364
      /// it does not accept inputs that are shorter, or with excess leading
365
      /// zero padding bytes.
366
      virtual std::optional<Scalar> deserialize_scalar(std::span<const uint8_t> bytes) const = 0;
367
368
      /// Reduce an integer modulo the group order
369
      ///
370
      /// The input can be at most twice the bit length of the order; if larger than this
371
      /// nullopt is returned
372
      virtual std::optional<Scalar> scalar_from_wide_bytes(std::span<const uint8_t> bytes) const = 0;
373
374
      virtual AffinePoint point_to_affine(const ProjectivePoint& pt) const = 0;
375
376
      virtual ProjectivePoint point_to_projective(const AffinePoint& pt) const = 0;
377
378
      virtual bool affine_point_is_identity(const AffinePoint& pt) const = 0;
379
380
      virtual ProjectivePoint point_double(const ProjectivePoint& pt) const = 0;
381
382
      virtual AffinePoint point_negate(const AffinePoint& pt) const = 0;
383
384
      virtual ProjectivePoint point_add(const ProjectivePoint& a, const ProjectivePoint& b) const = 0;
385
386
      virtual ProjectivePoint point_add_mixed(const ProjectivePoint& a, const AffinePoint& b) const = 0;
387
388
      virtual void serialize_point(std::span<uint8_t> bytes, const AffinePoint& pt) const = 0;
389
390
      virtual void serialize_point_compressed(std::span<uint8_t> bytes, const AffinePoint& pt) const = 0;
391
392
      virtual void serialize_point_x(std::span<uint8_t> bytes, const AffinePoint& pt) const = 0;
393
394
      virtual void serialize_scalar(std::span<uint8_t> bytes, const Scalar& scalar) const = 0;
395
396
      /**
397
      * Return the scalar zero
398
      */
399
      virtual Scalar scalar_zero() const = 0;
400
401
      /**
402
      * Return the scalar one
403
      */
404
      virtual Scalar scalar_one() const = 0;
405
406
      /**
407
      * Return a small scalar
408
      */
409
      virtual Scalar scalar_from_u32(uint32_t x) const = 0;
410
411
      virtual Scalar scalar_add(const Scalar& a, const Scalar& b) const = 0;
412
      virtual Scalar scalar_sub(const Scalar& a, const Scalar& b) const = 0;
413
      virtual Scalar scalar_mul(const Scalar& a, const Scalar& b) const = 0;
414
      virtual Scalar scalar_square(const Scalar& s) const = 0;
415
      virtual Scalar scalar_invert(const Scalar& s) const = 0;
416
      virtual Scalar scalar_negate(const Scalar& s) const = 0;
417
      virtual bool scalar_is_zero(const Scalar& s) const = 0;
418
      virtual bool scalar_equal(const Scalar& a, const Scalar& b) const = 0;
419
420
      /**
421
      * Return a new random scalar
422
      */
423
      virtual Scalar random_scalar(RandomNumberGenerator& rng) const = 0;
424
425
      /**
426
      * RFC 9380 hash to curve (NU variant)
427
      *
428
      * This is currently only supported for a few specific curves
429
      */
430
      virtual AffinePoint hash_to_curve_nu(std::string_view hash,
431
                                           std::span<const uint8_t> input,
432
                                           std::span<const uint8_t> domain_sep) const = 0;
433
434
      /**
435
      * RFC 9380 hash to curve (RO variant)
436
      *
437
      * This is currently only supported for a few specific curves
438
      */
439
      virtual ProjectivePoint hash_to_curve_ro(std::string_view hash,
440
                                               std::span<const uint8_t> input,
441
                                               std::span<const uint8_t> domain_sep) const = 0;
442
};
443
444
}  // namespace Botan::PCurve
445
446
#endif