Botan 3.13.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/concepts.h>
11#include <botan/secmem.h>
12#include <botan/types.h>
13#include <array>
14#include <functional>
15#include <memory>
16#include <optional>
17#include <span>
18#include <string_view>
19
20namespace Botan {
21
22class BigInt;
24
25} // namespace Botan
26
27namespace Botan::PCurve {
28
29/**
30* An elliptic curve without cofactor in Weierstrass form
31*/
32class PrimeOrderCurve /* NOLINT(*-special-member-functions) */ {
33 public:
34 /// Somewhat arbitrary maximum size for a field or scalar
35 ///
36 /// Sized to fit at least P-521
37 static constexpr size_t MaximumBitLength = 521;
38
39 static constexpr size_t MaximumByteLength = (MaximumBitLength + 7) / 8;
40
41 /// Number of words used to store MaximumByteLength
42 static constexpr size_t StorageWords = (MaximumByteLength + sizeof(word) - 1) / sizeof(word);
43
44 /// @returns nullptr if the curve specified is not available
45 static std::shared_ptr<const PrimeOrderCurve> for_named_curve(std::string_view name);
46
47 /// @returns nullptr if the parameters seem unsuitable for pcurves
48 /// for example if the prime is too large
49 ///
50 /// This function *should* accept the same subset of curves as
51 /// the EC_Group constructor that accepts BigInts.
52 static std::shared_ptr<const PrimeOrderCurve> from_params(const BigInt& p,
53 const BigInt& a,
54 const BigInt& b,
55 const BigInt& base_x,
56 const BigInt& base_y,
57 const BigInt& order);
58
59 typedef std::array<word, StorageWords> StorageUnit;
60 typedef std::shared_ptr<const PrimeOrderCurve> CurvePtr;
61
62 /// Elliptic curve scalar
63 ///
64 /// This refers to the set of integers modulo the (prime) group order
65 /// of the elliptic curve.
66 class Scalar final {
67 public:
68 Scalar(const Scalar& other) = default;
69 Scalar(Scalar&& other) = default;
70 Scalar& operator=(const Scalar& other) = default;
71 Scalar& operator=(Scalar&& other) = default;
72
73 // Scalars are commonly secret values so wipe on destruction
75
76 void _zeroize();
77
78 const auto& _curve() const { return m_curve; }
79
80 const auto& _value() const { return m_value; }
81
82 static Scalar _create(CurvePtr curve, StorageUnit v) { return Scalar(std::move(curve), v); }
83
84 private:
85 Scalar(CurvePtr curve, StorageUnit v) : m_curve(std::move(curve)), m_value(v) {}
86
87 CurvePtr m_curve;
88 StorageUnit m_value;
89 };
90
91 /**
92 * A point on the elliptic curve in affine form
93 *
94 * These points can be serialized, or converted to projective form for computation
95 */
96 class AffinePoint final {
97 public:
98 AffinePoint(const AffinePoint& other) = default;
99 AffinePoint(AffinePoint&& other) = default;
100 AffinePoint& operator=(const AffinePoint& other) = default;
101 AffinePoint& operator=(AffinePoint&& other) = default;
102 ~AffinePoint() = default;
103
104 static AffinePoint generator(const CurvePtr& curve) { return curve->generator(); }
105
106 const auto& _curve() const { return m_curve; }
107
108 const auto& _x() const { return m_x; }
109
110 const auto& _y() const { return m_y; }
111
113 return AffinePoint(std::move(curve), x, y);
114 }
115
116 private:
117 AffinePoint(CurvePtr curve, StorageUnit x, StorageUnit y) : m_curve(std::move(curve)), m_x(x), m_y(y) {}
118
119 CurvePtr m_curve;
120 StorageUnit m_x;
121 StorageUnit m_y;
122 };
123
124 /**
125 * A point on the elliptic curve in projective form
126 *
127 * This is a form that is convenient for computation; it must be converted to
128 * affine form for comparisons or serialization.
129 */
130 class ProjectivePoint final {
131 public:
132 ProjectivePoint(const ProjectivePoint& other) = default;
134 ProjectivePoint& operator=(const ProjectivePoint& other) = default;
136 ~ProjectivePoint() = default;
137
138 const auto& _curve() const { return m_curve; }
139
140 const auto& _x() const { return m_x; }
141
142 const auto& _y() const { return m_y; }
143
144 const auto& _z() const { return m_z; }
145
147 return ProjectivePoint(std::move(curve), x, y, z);
148 }
149
150 private:
152 m_curve(std::move(curve)), m_x(x), m_y(y), m_z(z) {}
153
154 CurvePtr m_curve;
155 StorageUnit m_x;
156 StorageUnit m_y;
157 StorageUnit m_z;
158 };
159
160 class PrecomputedMul2Table /* NOLINT(*-special-member-functions) */ {
161 public:
162 virtual ~PrecomputedMul2Table() = default;
163 };
164
165 virtual ~PrimeOrderCurve() = default;
166
167 /// Return the bit length of the group order
168 virtual size_t order_bits() const = 0;
169
170 /// Return the byte length of the scalar element
171 virtual size_t scalar_bytes() const = 0;
172
173 /// Return the byte length of a field element
174 ///
175 /// Each point consists of two field elements
176 virtual size_t field_element_bytes() const = 0;
177
178 /// Base point multiplication
179 ///
180 /// Multiply by the standard generator point g
181 virtual ProjectivePoint mul_by_g(const Scalar& scalar, RandomNumberGenerator& rng) const = 0;
182
183 /// Base point multiplication, returning only the x coordinate modulo the group order
184 ///
185 /// Multiply by the standard generator point g, then extract the x
186 /// coordinate as an integer, then reduce the x coordinate modulo the
187 /// group order
188 virtual Scalar base_point_mul_x_mod_order(const Scalar& scalar, RandomNumberGenerator& rng) const = 0;
189
190 /// Generic point multiplication
191 ///
192 /// Multiply an arbitrary point by a scalar
193 virtual ProjectivePoint mul(const AffinePoint& pt, const Scalar& scalar, RandomNumberGenerator& rng) const = 0;
194
195 /// Generic x-only point multiplication
196 ///
197 /// Multiply an arbitrary point by a scalar, returning only the x coordinate
199 const Scalar& scalar,
200 RandomNumberGenerator& rng) const = 0;
201
202 /// Setup a table for 2-ary multiplication where the first point is the generator
203 virtual std::unique_ptr<const PrecomputedMul2Table> mul2_setup_g(const AffinePoint& q) const = 0;
204
205 /// Perform 2-ary multiplication (variable time)
206 ///
207 /// Compute p*x + q*y in variable time
208 ///
209 /// Returns nullopt if the produced point is the point at infinity
210 virtual std::optional<ProjectivePoint> mul2_vartime(const PrecomputedMul2Table& table,
211 const Scalar& x,
212 const Scalar& y) const = 0;
213
214 /// Perform 2-ary multiplication (constant time)
215 ///
216 /// Compute p*x + q*y
217 ///
218 /// Returns nullopt if the produced point is the point at infinity
219 virtual std::optional<ProjectivePoint> mul_px_qy(const AffinePoint& p,
220 const Scalar& x,
221 const AffinePoint& q,
222 const Scalar& y,
223 RandomNumberGenerator& rng) const = 0;
224
225 /// Perform 2-ary multiplication (variable time), reducing x modulo order
226 ///
227 /// Compute p*x + q*y in variable time, then extract the x coordinate of
228 /// the result, and reduce x modulo the group order. Compare that value
229 /// with v. If equal, returns true. Otherwise returns false, including if
230 /// the produced point is the point at infinity
232 const Scalar& v,
233 const Scalar& x,
234 const Scalar& y) const = 0;
235
236 /// Return the standard generator
237 virtual AffinePoint generator() const = 0;
238
239 /// Return the identity element (aka the point at infinity)
240 virtual AffinePoint point_identity() const = 0;
241
242 /// Deserialize a point in the SEC1 uncompressed format
243 ///
244 /// The input must be exactly 1 + 2*field_element_bytes long and have a
245 /// header byte of 0x04. All other encodings are rejected, as are inputs
246 /// where (x,y) is not a point on the curve.
247 virtual std::optional<AffinePoint> deserialize_point_uncompressed(std::span<const uint8_t> bytes) const = 0;
248
249 /// Deserialize a point in the SEC1 compressed format
250 ///
251 /// The input must be exactly 1 + field_element_bytes long and have a
252 /// header byte of 0x02 or 0x03. All other encodings are rejected, as are
253 /// inputs where x is not the affine x coordinate of a point on the curve.
254 virtual std::optional<AffinePoint> deserialize_point_compressed(std::span<const uint8_t> bytes) const = 0;
255
256 /// Deserialize a scalar in [1,p)
257 ///
258 /// This function requires the input length be exactly scalar_bytes long;
259 /// it does not accept inputs that are shorter, or with excess leading
260 /// zero padding bytes.
261 ///
262 /// This function also rejects zero as an input, since in normal usage
263 /// scalars are integers in Z_p*
264 virtual std::optional<Scalar> deserialize_scalar(std::span<const uint8_t> bytes) const = 0;
265
266 /// Reduce an integer modulo the group order
267 ///
268 /// The input can be at most twice the bit length of the order; if larger than this
269 /// nullopt is returned
270 virtual std::optional<Scalar> scalar_from_wide_bytes(std::span<const uint8_t> bytes) const = 0;
271
272 virtual AffinePoint point_to_affine(const ProjectivePoint& pt) const = 0;
273
274 virtual bool affine_point_is_identity(const AffinePoint& pt) const = 0;
275
276 virtual AffinePoint point_negate(const AffinePoint& pt) const = 0;
277
278 virtual ProjectivePoint point_add(const AffinePoint& a, const AffinePoint& b) const = 0;
279
280 virtual void serialize_point(std::span<uint8_t> bytes, const AffinePoint& pt) const = 0;
281
282 virtual void serialize_scalar(std::span<uint8_t> bytes, const Scalar& scalar) const = 0;
283
284 /**
285 * Return the scalar one
286 */
287 virtual Scalar scalar_one() const = 0;
288
289 /// Scalar addition
290 virtual Scalar scalar_add(const Scalar& a, const Scalar& b) const = 0;
291
292 /// Scalar subtraction
293 virtual Scalar scalar_sub(const Scalar& a, const Scalar& b) const = 0;
294
295 /// Scalar multiplication
296 virtual Scalar scalar_mul(const Scalar& a, const Scalar& b) const = 0;
297
298 /// Scalar squaring
299 virtual Scalar scalar_square(const Scalar& s) const = 0;
300
301 /// Scalar inversion
302 virtual Scalar scalar_invert(const Scalar& s) const = 0;
303
304 /// Scalar inversion (variable time)
305 virtual Scalar scalar_invert_vartime(const Scalar& s) const = 0;
306
307 /// Scalar negation
308 virtual Scalar scalar_negate(const Scalar& s) const = 0;
309
310 /// Test if scalar is zero
311 virtual bool scalar_is_zero(const Scalar& s) const = 0;
312
313 /// Test if two scalars are equal
314 virtual bool scalar_equal(const Scalar& a, const Scalar& b) const = 0;
315
316 /**
317 * Return a new random scalar
318 */
320
321 /**
322 * Return true if this curve supports RFC 9380 hash to curve
323 *
324 * If this returns false then hash_to_curve_nu and hash_to_curve_ro
325 * will throw Not_Implemented
326 */
327 virtual bool supports_hash_to_curve() const = 0;
328
329 /**
330 * RFC 9380 hash to curve (NU variant)
331 *
332 * This is currently only supported for a few specific curves
333 *
334 * @param expand_message is a callback which must fill the provided output
335 * span with a sequence of uniform bytes, or if this is not possible due to
336 * length limitations or some other issue, throw an exception. It is
337 * invoked to produce the `uniform_bytes` value; see RFC 9380 section 5.2
338 */
339 virtual AffinePoint hash_to_curve_nu(std::function<void(std::span<uint8_t>)> expand_message) const = 0;
340
341 /**
342 * RFC 9380 hash to curve (RO variant)
343 *
344 * This is currently only supported for a few specific curves
345 *
346 * @param expand_message is a callback which must fill the provided output
347 * span with a sequence of uniform bytes, or if this is not possible due to
348 * length limitations or some other issue, throw an exception. It is
349 * invoked to produce the `uniform_bytes` value; see RFC 9380 section 5.2
350 */
351 virtual ProjectivePoint hash_to_curve_ro(std::function<void(std::span<uint8_t>)> expand_message) const = 0;
352};
353
354} // namespace Botan::PCurve
355
356#endif
AffinePoint & operator=(const AffinePoint &other)=default
static AffinePoint _create(CurvePtr curve, StorageUnit x, StorageUnit y)
Definition pcurves.h:112
AffinePoint(AffinePoint &&other)=default
AffinePoint & operator=(AffinePoint &&other)=default
static AffinePoint generator(const CurvePtr &curve)
Definition pcurves.h:104
AffinePoint(const AffinePoint &other)=default
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:146
Scalar(const Scalar &other)=default
Scalar & operator=(Scalar &&other)=default
Scalar & operator=(const Scalar &other)=default
static Scalar _create(CurvePtr curve, StorageUnit v)
Definition pcurves.h:82
virtual ~PrimeOrderCurve()=default
virtual Scalar scalar_add(const Scalar &a, const Scalar &b) const =0
Scalar addition.
virtual AffinePoint point_negate(const AffinePoint &pt) const =0
virtual void serialize_point(std::span< uint8_t > bytes, const AffinePoint &pt) const =0
virtual std::unique_ptr< const PrecomputedMul2Table > mul2_setup_g(const AffinePoint &q) const =0
Setup a table for 2-ary multiplication where the first point is the generator.
virtual ProjectivePoint hash_to_curve_ro(std::function< void(std::span< uint8_t >)> expand_message) const =0
virtual bool supports_hash_to_curve() const =0
virtual size_t field_element_bytes() const =0
static constexpr size_t StorageWords
Number of words used to store MaximumByteLength.
Definition pcurves.h:42
virtual size_t order_bits() const =0
Return the bit length of the group order.
std::shared_ptr< const PrimeOrderCurve > CurvePtr
Definition pcurves.h:60
virtual AffinePoint point_identity() const =0
Return the identity element (aka the point at infinity).
virtual size_t scalar_bytes() const =0
Return the byte length of the scalar element.
virtual ProjectivePoint point_add(const AffinePoint &a, const AffinePoint &b) const =0
std::array< word, StorageWords > StorageUnit
Definition pcurves.h:59
virtual bool scalar_is_zero(const Scalar &s) const =0
Test if scalar is zero.
virtual std::optional< ProjectivePoint > mul2_vartime(const PrecomputedMul2Table &table, const Scalar &x, const Scalar &y) 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
Scalar inversion.
virtual Scalar scalar_mul(const Scalar &a, const Scalar &b) const =0
Scalar multiplication.
virtual Scalar random_scalar(RandomNumberGenerator &rng) const =0
virtual secure_vector< uint8_t > mul_x_only(const AffinePoint &pt, const Scalar &scalar, RandomNumberGenerator &rng) const =0
virtual bool mul2_vartime_x_mod_order_eq(const PrecomputedMul2Table &table, const Scalar &v, const Scalar &x, const Scalar &y) const =0
virtual std::optional< AffinePoint > deserialize_point_compressed(std::span< const uint8_t > bytes) 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 Scalar scalar_negate(const Scalar &s) const =0
Scalar negation.
static constexpr size_t MaximumByteLength
Definition pcurves.h:39
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< AffinePoint > deserialize_point_uncompressed(std::span< const uint8_t > bytes) const =0
virtual ProjectivePoint mul(const AffinePoint &pt, const Scalar &scalar, RandomNumberGenerator &rng) const =0
virtual Scalar scalar_invert_vartime(const Scalar &s) const =0
Scalar inversion (variable time).
virtual Scalar scalar_square(const Scalar &s) const =0
Scalar squaring.
virtual bool scalar_equal(const Scalar &a, const Scalar &b) const =0
Test if two scalars are equal.
virtual AffinePoint hash_to_curve_nu(std::function< void(std::span< uint8_t >)> expand_message) const =0
virtual std::optional< ProjectivePoint > mul_px_qy(const AffinePoint &p, const Scalar &x, const AffinePoint &q, const Scalar &y, RandomNumberGenerator &rng) const =0
static constexpr size_t MaximumBitLength
Definition pcurves.h:37
virtual bool affine_point_is_identity(const AffinePoint &pt) const =0
static std::shared_ptr< const PrimeOrderCurve > from_params(const BigInt &p, const BigInt &a, const BigInt &b, const BigInt &base_x, const BigInt &base_y, const BigInt &order)
Definition pcurves.cpp:21
static std::shared_ptr< const PrimeOrderCurve > for_named_curve(std::string_view name)
Definition pcurves.cpp:32
virtual Scalar base_point_mul_x_mod_order(const Scalar &scalar, RandomNumberGenerator &rng) 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
Scalar subtraction.
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128
std::conditional_t< HasNative64BitRegisters, std::uint64_t, uint32_t > word
The native machine word, used as the limb type for multiprecision integers.
Definition types.h:131