Botan 3.5.0
Crypto and TLS for C&
pcurves.h
Go to the documentation of this file.
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
21namespace Botan {
22
23class RandomNumberGenerator;
24
25} // namespace Botan
26
27namespace Botan::PCurve {
28
29/**
30* An elliptic curve without cofactor in Weierstrass form
31*/
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 static std::shared_ptr<const PrimeOrderCurve> from_name(std::string_view name) {
45 if(auto id = PrimeOrderCurveId::from_string(name)) {
46 return PrimeOrderCurve::from_id(id.value());
47 } else {
48 return {};
49 }
50 }
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 Scalar(const Scalar& other) = default;
64 Scalar(Scalar&& other) = default;
65 Scalar& operator=(const Scalar& other) = default;
66 Scalar& operator=(Scalar&& other) = default;
67 ~Scalar() = default;
68
69 /**
70 * Return the size of the byte encoding of Scalars
71 */
72 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 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 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 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 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 Scalar negate() const { return m_curve->scalar_negate(*this); }
108
109 /**
110 * Square modulo the group order
111 */
112 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 Scalar invert() const { return m_curve->scalar_invert(*this); }
120
121 /**
122 * Returns true if this is equal to zero
123 */
124 bool is_zero() const { return m_curve->scalar_is_zero(*this); }
125
126 const auto& _curve() const { return m_curve; }
127
128 const auto& _value() const { return m_value; }
129
130 static Scalar _create(CurvePtr curve, StorageUnit v) { return Scalar(std::move(curve), v); }
131
132 private:
133 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 */
145 public:
146 AffinePoint(const AffinePoint& other) = default;
147 AffinePoint(AffinePoint&& other) = default;
148 AffinePoint& operator=(const AffinePoint& other) = default;
149 AffinePoint& operator=(AffinePoint&& other) = default;
150 ~AffinePoint() = default;
151
152 static AffinePoint generator(CurvePtr curve) { return curve->generator(); }
153
154 /**
155 * Return the size of the uncompressed encoding of points
156 */
157 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 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 T serialize() const {
169 T bytes(this->bytes());
170 m_curve->serialize_point(bytes, *this);
171 return bytes;
172 }
173
174 /**
175 * Return the serialization of the point in compressed form
176 */
177 template <concepts::resizable_byte_buffer T = std::vector<uint8_t>>
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 * Return true if this is the curve identity element (aka the point at infinity)
196 */
197 bool is_identity() const { return m_curve->affine_point_is_identity(*this); }
198
199 const auto& _curve() const { return m_curve; }
200
201 const auto& _x() const { return m_x; }
202
203 const auto& _y() const { return m_y; }
204
206 return AffinePoint(std::move(curve), x, y);
207 }
208
209 private:
210 AffinePoint(CurvePtr curve, StorageUnit x, StorageUnit y) : m_curve(std::move(curve)), m_x(x), m_y(y) {}
211
212 CurvePtr m_curve;
213 StorageUnit m_x;
214 StorageUnit m_y;
215 };
216
217 /**
218 * A point on the elliptic curve in projective form
219 *
220 * This is a form that is convenient for computation; it must be converted to
221 * affine form for comparisons or serialization.
222 */
224 public:
225 ProjectivePoint(const ProjectivePoint& other) = default;
227 ProjectivePoint& operator=(const ProjectivePoint& other) = default;
229 ~ProjectivePoint() = default;
230
231 /**
232 * Convert a point from affine to projective form
233 */
234 static ProjectivePoint from_affine(const AffinePoint& pt) { return pt._curve()->point_to_projective(pt); }
235
236 /**
237 * Convert a point from projective to affine form
238 *
239 * This operation is expensive; perform it only when required for
240 * serialization
241 */
242 AffinePoint to_affine() const { return m_curve->point_to_affine(*this); }
243
244 ProjectivePoint dbl() const { return m_curve->point_double(*this); }
245
246 ProjectivePoint negate() const { return m_curve->point_negate(*this); }
247
249 return x.m_curve->point_add(x, y);
250 }
251
253 return x.m_curve->point_add_mixed(x, y);
254 }
255
256 const auto& _curve() const { return m_curve; }
257
258 const auto& _x() const { return m_x; }
259
260 const auto& _y() const { return m_y; }
261
262 const auto& _z() const { return m_z; }
263
265 return ProjectivePoint(std::move(curve), x, y, z);
266 }
267
268 private:
270 m_curve(std::move(curve)), m_x(x), m_y(y), m_z(z) {}
271
272 CurvePtr m_curve;
273 StorageUnit m_x;
274 StorageUnit m_y;
275 StorageUnit m_z;
276 };
277
279 public:
280 virtual ~PrecomputedMul2Table() = default;
281 };
282
283 virtual ~PrimeOrderCurve() = default;
284
285 /// Return the bit length of the group order
286 virtual size_t order_bits() const = 0;
287
288 /// Return the byte length of the scalar element
289 virtual size_t scalar_bytes() const = 0;
290
291 /// Return the byte length of a field element
292 ///
293 /// Each point consists of two field elements
294 virtual size_t field_element_bytes() const = 0;
295
296 /// Base point multiplication
297 ///
298 /// Multiply by the standard generator point g
299 virtual ProjectivePoint mul_by_g(const Scalar& scalar, RandomNumberGenerator& rng) const = 0;
300
301 /// Base point multiplication, returning only the x coordinate modulo the group order
302 ///
303 /// Multiply by the standard generator point g, then extract the x
304 /// coordinate as an integer, then reduce the x coordinate modulo the
305 /// group order
306 virtual Scalar base_point_mul_x_mod_order(const Scalar& scalar, RandomNumberGenerator& rng) const = 0;
307
308 /// Generic point multiplication
309 ///
310 /// Multiply an arbitrary point by a scalar
311 virtual ProjectivePoint mul(const AffinePoint& pt, const Scalar& scalar, RandomNumberGenerator& rng) const = 0;
312
313 /// Setup a table for 2-ary multiplication
314 virtual std::unique_ptr<const PrecomputedMul2Table> mul2_setup(const AffinePoint& pt1,
315 const AffinePoint& pt2) const = 0;
316
317 /// Perform 2-ary multiplication (variable time)
318 ///
319 /// Compute s1*pt1 + s2*pt2 in variable time
320 ///
321 /// Returns nullopt if the produced point is the point at infinity
322 virtual std::optional<ProjectivePoint> mul2_vartime(const PrecomputedMul2Table& table,
323 const Scalar& s1,
324 const Scalar& s2) const = 0;
325
326 /// Perform 2-ary multiplication (variable time), reducing x modulo order
327 ///
328 /// Compute s1*pt1 + s2*pt2 in variable time, then extract the x coordinate
329 /// of the result, and reduce x modulo the group order
330 ///
331 /// Returns nullopt if the produced point is the point at infinity
332 virtual std::optional<Scalar> mul2_vartime_x_mod_order(const PrecomputedMul2Table& table,
333 const Scalar& s1,
334 const Scalar& s2) const = 0;
335
336 /// Return the standard generator
337 virtual AffinePoint generator() const = 0;
338
339 /// Deserialize a point
340 ///
341 /// Both compressed and uncompressed encodings are accepted
342 ///
343 /// Note that the deprecated "hybrid" encoding is not supported here
344 virtual std::optional<AffinePoint> deserialize_point(std::span<const uint8_t> bytes) const = 0;
345
346 /// Deserialize a scalar
347 ///
348 /// This function requires the input length be exactly scalar_bytes long;
349 /// it does not accept inputs that are shorter, or with excess leading
350 /// zero padding bytes.
351 virtual std::optional<Scalar> deserialize_scalar(std::span<const uint8_t> bytes) const = 0;
352
353 /// Deserialize a scalar using ECDSA truncation rules
354 ///
355 /// ECDSA and other signature schemes use a specific rule for converting a hash
356 /// output into a scalar.
357 virtual Scalar scalar_from_bits_with_trunc(std::span<const uint8_t> bytes) const = 0;
358
359 /// Reduce an integer modulo the group order
360 ///
361 /// The input can be at most twice the bit length of the order; if larger than this
362 /// nullopt is returned
363 virtual std::optional<Scalar> scalar_from_wide_bytes(std::span<const uint8_t> bytes) const = 0;
364
365 virtual AffinePoint point_to_affine(const ProjectivePoint& pt) const = 0;
366
367 virtual ProjectivePoint point_to_projective(const AffinePoint& pt) const = 0;
368
369 virtual bool affine_point_is_identity(const AffinePoint& pt) const = 0;
370
371 virtual ProjectivePoint point_double(const ProjectivePoint& pt) const = 0;
372
373 virtual ProjectivePoint point_negate(const ProjectivePoint& pt) const = 0;
374
375 virtual ProjectivePoint point_add(const ProjectivePoint& a, const ProjectivePoint& b) const = 0;
376
377 virtual ProjectivePoint point_add_mixed(const ProjectivePoint& a, const AffinePoint& b) const = 0;
378
379 virtual void serialize_point(std::span<uint8_t> bytes, const AffinePoint& pt) const = 0;
380
381 virtual void serialize_point_compressed(std::span<uint8_t> bytes, const AffinePoint& pt) const = 0;
382
383 virtual void serialize_point_x(std::span<uint8_t> bytes, const AffinePoint& pt) const = 0;
384
385 virtual void serialize_scalar(std::span<uint8_t> bytes, const Scalar& scalar) const = 0;
386
387 /**
388 * Return the scalar zero
389 */
390 virtual Scalar scalar_zero() const = 0;
391
392 /**
393 * Return the scalar one
394 */
395 virtual Scalar scalar_one() const = 0;
396
397 /**
398 * Return a small scalar
399 */
400 virtual Scalar scalar_from_u32(uint32_t x) const = 0;
401
402 virtual Scalar scalar_add(const Scalar& a, const Scalar& b) const = 0;
403 virtual Scalar scalar_sub(const Scalar& a, const Scalar& b) const = 0;
404 virtual Scalar scalar_mul(const Scalar& a, const Scalar& b) const = 0;
405 virtual Scalar scalar_square(const Scalar& s) const = 0;
406 virtual Scalar scalar_invert(const Scalar& s) const = 0;
407 virtual Scalar scalar_negate(const Scalar& s) const = 0;
408 virtual bool scalar_is_zero(const Scalar& s) const = 0;
409 virtual bool scalar_equal(const Scalar& a, const Scalar& b) const = 0;
410
411 /**
412 * Return a new random scalar
413 */
415
416 /**
417 * RFC 9380 hash to curve
418 *
419 * This is currently only supported for a few specific curves
420 */
421 virtual ProjectivePoint hash_to_curve(std::string_view hash,
422 std::span<const uint8_t> input,
423 std::span<const uint8_t> domain_sep,
424 bool random_oracle) const = 0;
425};
426
427} // namespace Botan::PCurve
428
429#endif
Identifier for a named prime order curve.
Definition pcurves_id.h:27
AffinePoint & operator=(const AffinePoint &other)=default
static AffinePoint generator(CurvePtr curve)
Definition pcurves.h:152
static AffinePoint _create(CurvePtr curve, StorageUnit x, StorageUnit y)
Definition pcurves.h:205
AffinePoint(AffinePoint &&other)=default
AffinePoint & operator=(AffinePoint &&other)=default
AffinePoint(const AffinePoint &other)=default
friend ProjectivePoint operator+(const ProjectivePoint &x, const AffinePoint &y)
Definition pcurves.h:252
ProjectivePoint & operator=(const ProjectivePoint &other)=default
ProjectivePoint(const ProjectivePoint &other)=default
ProjectivePoint(ProjectivePoint &&other)=default
ProjectivePoint & operator=(ProjectivePoint &&other)=default
static ProjectivePoint _create(CurvePtr curve, StorageUnit x, StorageUnit y, StorageUnit z)
Definition pcurves.h:264
friend ProjectivePoint operator+(const ProjectivePoint &x, const ProjectivePoint &y)
Definition pcurves.h:248
static ProjectivePoint from_affine(const AffinePoint &pt)
Definition pcurves.h:234
Scalar(const Scalar &other)=default
friend Scalar operator-(const Scalar &a, const Scalar &b)
Definition pcurves.h:97
friend Scalar operator*(const Scalar &a, const Scalar &b)
Definition pcurves.h:87
Scalar & operator=(Scalar &&other)=default
Scalar & operator=(const Scalar &other)=default
friend bool operator==(const Scalar &a, const Scalar &b)
Definition pcurves.h:102
static Scalar _create(CurvePtr curve, StorageUnit v)
Definition pcurves.h:130
friend Scalar operator+(const Scalar &a, const Scalar &b)
Definition pcurves.h:92
virtual ~PrimeOrderCurve()=default
virtual Scalar scalar_from_bits_with_trunc(std::span< const uint8_t > bytes) const =0
virtual Scalar scalar_add(const Scalar &a, const Scalar &b) const =0
virtual std::unique_ptr< const PrecomputedMul2Table > mul2_setup(const AffinePoint &pt1, const AffinePoint &pt2) const =0
Setup a table for 2-ary multiplication.
virtual void serialize_point(std::span< uint8_t > bytes, const AffinePoint &pt) const =0
virtual std::optional< AffinePoint > deserialize_point(std::span< const uint8_t > bytes) const =0
virtual Scalar scalar_zero() const =0
virtual size_t field_element_bytes() const =0
virtual ProjectivePoint hash_to_curve(std::string_view hash, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep, bool random_oracle) const =0
virtual size_t order_bits() const =0
Return the bit length of the group order.
std::shared_ptr< const PrimeOrderCurve > CurvePtr
Definition pcurves.h:55
virtual size_t scalar_bytes() const =0
Return the byte length of the scalar element.
virtual std::optional< Scalar > mul2_vartime_x_mod_order(const PrecomputedMul2Table &table, const Scalar &s1, const Scalar &s2) const =0
std::array< word, StorageWords > StorageUnit
Definition pcurves.h:54
virtual bool scalar_is_zero(const Scalar &s) const =0
virtual std::optional< Scalar > deserialize_scalar(std::span< const uint8_t > bytes) const =0
virtual Scalar scalar_invert(const Scalar &s) const =0
virtual Scalar scalar_mul(const Scalar &a, const Scalar &b) const =0
virtual void serialize_point_compressed(std::span< uint8_t > bytes, const AffinePoint &pt) const =0
virtual Scalar scalar_from_u32(uint32_t x) const =0
virtual Scalar random_scalar(RandomNumberGenerator &rng) const =0
virtual AffinePoint point_to_affine(const ProjectivePoint &pt) const =0
virtual AffinePoint generator() const =0
Return the standard generator.
virtual Scalar scalar_one() const =0
virtual ProjectivePoint point_negate(const ProjectivePoint &pt) const =0
virtual Scalar scalar_negate(const Scalar &s) const =0
virtual void serialize_point_x(std::span< uint8_t > bytes, const AffinePoint &pt) const =0
virtual ProjectivePoint mul_by_g(const Scalar &scalar, RandomNumberGenerator &rng) const =0
virtual std::optional< Scalar > scalar_from_wide_bytes(std::span< const uint8_t > bytes) const =0
virtual std::optional< ProjectivePoint > mul2_vartime(const PrecomputedMul2Table &table, const Scalar &s1, const Scalar &s2) const =0
virtual ProjectivePoint point_to_projective(const AffinePoint &pt) const =0
static std::shared_ptr< const PrimeOrderCurve > from_name(std::string_view name)
Definition pcurves.h:44
virtual ProjectivePoint mul(const AffinePoint &pt, const Scalar &scalar, RandomNumberGenerator &rng) const =0
virtual Scalar scalar_square(const Scalar &s) const =0
virtual bool scalar_equal(const Scalar &a, const Scalar &b) const =0
virtual ProjectivePoint point_add_mixed(const ProjectivePoint &a, const AffinePoint &b) const =0
virtual bool affine_point_is_identity(const AffinePoint &pt) const =0
virtual Scalar base_point_mul_x_mod_order(const Scalar &scalar, RandomNumberGenerator &rng) const =0
virtual ProjectivePoint point_add(const ProjectivePoint &a, const ProjectivePoint &b) const =0
virtual void serialize_scalar(std::span< uint8_t > bytes, const Scalar &scalar) const =0
virtual Scalar scalar_sub(const Scalar &a, const Scalar &b) const =0
virtual ProjectivePoint point_double(const ProjectivePoint &pt) const =0
std::string name
int(* final)(unsigned char *, CTX *)
#define BOTAN_TEST_API
Definition compiler.h:51
FE_25519 T
Definition ge.cpp:34
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61