Botan 3.13.0
Crypto and TLS for C&
ec_apoint.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_EC_APOINT_H_
8#define BOTAN_EC_APOINT_H_
9
10#include <botan/concepts.h>
11#include <botan/ec_point_format.h>
12#include <botan/secmem.h>
13#include <botan/types.h>
14#include <memory>
15#include <optional>
16#include <span>
17#include <string_view>
18#include <vector>
19
20namespace Botan {
21
22class BigInt;
24class EC_Group;
25class EC_Scalar;
26
27#if defined(BOTAN_HAS_LEGACY_EC_POINT)
28class EC_Point;
29#endif
30
31class EC_Group_Data;
33
34/**
35* Elliptic Curve Point in Affine Representation
36*/
38 public:
39 /// Point deserialization. Throws if wrong length or not a valid point
40 ///
41 /// This accepts SEC1 compressed or uncompressed formats. It also (for
42 /// backward compatibility) accepts the deprecated hybrid format, and
43 /// the encoding of the identity element as a single zero byte. Prefer
44 /// deserialize_compressed or deserialize_uncompressed, which accept
45 /// exactly one well-defined encoding.
46 EC_AffinePoint(const EC_Group& group, std::span<const uint8_t> bytes);
47
48 /// Point deserialization. Returns nullopt if wrong length or not a valid point
49 ///
50 /// This accepts SEC1 compressed or uncompressed formats. It also (for
51 /// backward compatibility) accepts the deprecated hybrid format, and
52 /// the encoding of the identity element as a single zero byte. Prefer
53 /// deserialize_compressed or deserialize_uncompressed, which accept
54 /// exactly one well-defined encoding.
55 static std::optional<EC_AffinePoint> deserialize(const EC_Group& group, std::span<const uint8_t> bytes);
56
57 /// Point deserialization, accepting only the SEC1 compressed format
58 ///
59 /// The encoding must be exactly 1 + field_element_bytes long, with a
60 /// header byte of either 0x02 or 0x03. All other encodings (including
61 /// the uncompressed, hybrid, and identity encodings) are rejected.
62 ///
63 /// Returns nullopt if the encoding was rejected or not a valid point
64 static std::optional<EC_AffinePoint> deserialize_compressed(const EC_Group& group,
65 std::span<const uint8_t> bytes);
66
67 /// Point deserialization, accepting only the SEC1 uncompressed format
68 ///
69 /// The encoding must be exactly 1 + 2*field_element_bytes long, with a
70 /// header byte of 0x04. All other encodings (including the compressed,
71 /// hybrid, and identity encodings) are rejected.
72 ///
73 /// Returns nullopt if the encoding was rejected or not a valid point
74 static std::optional<EC_AffinePoint> deserialize_uncompressed(const EC_Group& group,
75 std::span<const uint8_t> bytes);
76
77 /// Create a point from a pair (x,y) of integers
78 ///
79 /// The integers must be within the field - in the range [0,p) and must
80 /// satisfy the curve equation
81 static std::optional<EC_AffinePoint> from_bigint_xy(const EC_Group& group, const BigInt& x, const BigInt& y);
82
83 /// Multiply by the group generator returning a complete point
84 static EC_AffinePoint g_mul(const EC_Scalar& scalar, RandomNumberGenerator& rng);
85
86 /// Return the identity element
87 static EC_AffinePoint identity(const EC_Group& group);
88
89 /// Return the standard group generator
90 static EC_AffinePoint generator(const EC_Group& group);
91
92 /// Hash to curve (RFC 9380), random oracle variant
93 ///
94 /// Only supported for specific groups
95 static EC_AffinePoint hash_to_curve_ro(const EC_Group& group,
96 std::string_view hash_fn,
97 std::span<const uint8_t> input,
98 std::span<const uint8_t> domain_sep);
99
100 /// Hash to curve (RFC 9380), random oracle variant
101 ///
102 /// Only supported for specific groups
103 static EC_AffinePoint hash_to_curve_ro(const EC_Group& group,
104 std::string_view hash_fn,
105 std::span<const uint8_t> input,
106 std::string_view domain_sep);
107
108 /// Hash to curve (RFC 9380), non uniform variant
109 ///
110 /// Only supported for specific groups
111 static EC_AffinePoint hash_to_curve_nu(const EC_Group& group,
112 std::string_view hash_fn,
113 std::span<const uint8_t> input,
114 std::span<const uint8_t> domain_sep);
115
116 /// Hash to curve (RFC 9380), non uniform variant
117 ///
118 /// Only supported for specific groups
119 static EC_AffinePoint hash_to_curve_nu(const EC_Group& group,
120 std::string_view hash_fn,
121 std::span<const uint8_t> input,
122 std::string_view domain_sep);
123
124 /// Multiply a point by a scalar returning a complete point
125 EC_AffinePoint mul(const EC_Scalar& scalar, RandomNumberGenerator& rng) const;
126
127 /// Multiply a point by a scalar, returning the byte encoding of the x coordinate only
129
130 /// Compute 2-ary multiscalar multiplication - p*x + q*y
131 ///
132 /// This operation runs in constant time with respect to p, x, q, and y
133 ///
134 /// @returns p*x+q*y, or nullopt if the result was the point at infinity
135 static std::optional<EC_AffinePoint> mul_px_qy(const EC_AffinePoint& p,
136 const EC_Scalar& x,
137 const EC_AffinePoint& q,
138 const EC_Scalar& y,
140
141 /// Point addition
142 ///
143 /// Note that this is quite slow since it converts the resulting
144 /// projective point immediately to affine coordinates, which requires a
145 /// field inversion. This can be sufficient when implementing protocols
146 /// that just need to perform a few additions.
147 ///
148 /// In the future a corresponding EC_ProjectivePoint type may be added
149 /// which would avoid the expensive affine conversions
150 EC_AffinePoint add(const EC_AffinePoint& q) const;
151
152 /// Point negation
153 EC_AffinePoint negate() const;
154
155 /// Return the number of bytes of a field element
156 ///
157 /// A point consists of two field elements, plus possibly a header
158 size_t field_element_bytes() const;
159
160 /// Return true if this point is the identity element
161 bool is_identity() const;
162
163 /// Write the fixed length encoding of affine x coordinate
164 ///
165 /// The output span must be exactly field_element_bytes long
166 ///
167 /// This function will fail if this point is the identity element
168 void serialize_x_to(std::span<uint8_t> bytes) const;
169
170 /// Write the fixed length encoding of affine y coordinate
171 ///
172 /// The output span must be exactly field_element_bytes long
173 ///
174 /// This function will fail if this point is the identity element
175 void serialize_y_to(std::span<uint8_t> bytes) const;
176
177 /// Write the fixed length encoding of affine x and y coordinates
178 ///
179 /// The output span must be exactly 2*field_element_bytes long
180 ///
181 /// This function will fail if this point is the identity element
182 void serialize_xy_to(std::span<uint8_t> bytes) const;
183
184 /// Write the fixed length SEC1 compressed encoding
185 ///
186 /// The output span must be exactly 1 + field_element_bytes long
187 ///
188 /// This function will fail if this point is the identity element
189 void serialize_compressed_to(std::span<uint8_t> bytes) const;
190
191 /// Return the fixed length encoding of SEC1 uncompressed encoding
192 ///
193 /// The output span must be exactly 1 + 2*field_element_bytes long
194 ///
195 /// This function will fail if this point is the identity element
196 void serialize_uncompressed_to(std::span<uint8_t> bytes) const;
197
198 /// Return the bytes of the affine x coordinate in a container
199 ///
200 /// This function will fail if this point is the identity element
201 template <concepts::resizable_byte_buffer T = secure_vector<uint8_t>>
202 T x_bytes() const {
203 T bytes(this->field_element_bytes());
204 this->serialize_x_to(bytes);
205 return bytes;
206 }
207
208 /// Return the bytes of the affine y coordinate in a container
209 ///
210 /// This function will fail if this point is the identity element
211 template <concepts::resizable_byte_buffer T = secure_vector<uint8_t>>
212 T y_bytes() const {
213 T bytes(this->field_element_bytes());
214 this->serialize_y_to(bytes);
215 return bytes;
216 }
217
218 /// Return the bytes of the affine x and y coordinates in a container
219 ///
220 /// This function will fail if this point is the identity element
221 template <concepts::resizable_byte_buffer T = secure_vector<uint8_t>>
222 T xy_bytes() const {
223 T bytes(2 * this->field_element_bytes());
224 this->serialize_xy_to(bytes);
225 return bytes;
226 }
227
228 /// Return the bytes of the affine x and y coordinates in a container
229 ///
230 /// This function will fail if this point is the identity element
231 template <concepts::resizable_byte_buffer T = std::vector<uint8_t>>
233 T bytes(1 + 2 * this->field_element_bytes());
234 this->serialize_uncompressed_to(bytes);
235 return bytes;
236 }
237
238 /// Return the bytes of the affine x and y coordinates in a container
239 ///
240 /// This function will fail if this point is the identity element
241 template <concepts::resizable_byte_buffer T = std::vector<uint8_t>>
243 T bytes(1 + this->field_element_bytes());
244 this->serialize_compressed_to(bytes);
245 return bytes;
246 }
247
248 /**
249 * Test if two points are equal
250 * @param other the point to compare against
251 * @return true if the two points are equal
252 */
253 bool operator==(const EC_AffinePoint& other) const;
254
255 /**
256 * Test if two points are unequal
257 * @param other the point to compare against
258 * @return true if the two points are not equal
259 */
260 bool operator!=(const EC_AffinePoint& other) const { return !(*this == other); }
261
262 /// Return an encoding depending on the requested format
263 std::vector<uint8_t> serialize(EC_Point_Format format) const;
264
265 /**
266 * Copy constructor
267 * @param other the point to copy
268 */
269 EC_AffinePoint(const EC_AffinePoint& other);
270
271 /**
272 * Move constructor
273 * @param other the point to move from
274 */
275 EC_AffinePoint(EC_AffinePoint&& other) noexcept;
276
277 /**
278 * Copy assignment
279 * @param other the point to copy
280 * @return reference to this
281 */
282 EC_AffinePoint& operator=(const EC_AffinePoint& other);
283
284 /**
285 * Move assignment
286 * @param other the point to move from
287 * @return reference to this
288 */
289 EC_AffinePoint& operator=(EC_AffinePoint&& other) noexcept;
290
291#if defined(BOTAN_HAS_LEGACY_EC_POINT)
292 /**
293 * Deprecated conversion
294 */
295 EC_AffinePoint(const EC_Group& group, const EC_Point& pt);
296
297 /**
298 * Deprecated conversion
299 */
300 EC_Point to_legacy_point() const;
301#endif
302
303 /**
304 * Multiply by the group generator returning a complete point
305 * @param scalar the scalar to multiply the generator by
306 * @param rng a random number generator, used for blinding
307 * @return the resulting point
308 */
309 BOTAN_DEPRECATED("Use version without workspace arg")
310 static EC_AffinePoint g_mul(const EC_Scalar& scalar, RandomNumberGenerator& rng, std::vector<BigInt>& /*ws*/) {
311 return EC_AffinePoint::g_mul(scalar, rng);
312 }
313
314 /**
315 * Multiply a point by a scalar returning a complete point
316 * @param scalar the scalar to multiply this point by
317 * @param rng a random number generator, used for blinding
318 * @return the resulting point
319 */
320 BOTAN_DEPRECATED("Use version without workspace arg")
321 EC_AffinePoint mul(const EC_Scalar& scalar, RandomNumberGenerator& rng, std::vector<BigInt>& /*ws*/) const {
322 return this->mul(scalar, rng);
323 }
324
325 /// Multiply a point by a scalar, returning the byte encoding of the x coordinate only
328 std::vector<BigInt>& /*ws*/) const {
329 return this->mul_x_only(scalar, rng);
330 }
331
333
334 /**
335 * For internal use only
336 */
337 const EC_AffinePoint_Data& _inner() const { return inner(); }
338
339 /**
340 * For internal use only
341 */
342 static EC_AffinePoint _from_inner(std::unique_ptr<EC_AffinePoint_Data> inner);
343
344 /**
345 * For internal use only
346 */
347 const std::shared_ptr<const EC_Group_Data>& _group() const;
348
349 private:
350 friend class EC_Mul2Table;
351
352 explicit EC_AffinePoint(std::unique_ptr<EC_AffinePoint_Data> point);
353
354 const EC_AffinePoint_Data& inner() const { return *m_point; }
355
356 std::unique_ptr<EC_AffinePoint_Data> m_point;
357};
358
359} // namespace Botan
360
361#endif
#define BOTAN_PUBLIC_API(maj, min)
Definition api.h:21
#define BOTAN_DEPRECATED(msg)
Definition api.h:73
static EC_AffinePoint hash_to_curve_ro(const EC_Group &group, std::string_view hash_fn, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep)
EC_AffinePoint negate() const
Point negation.
size_t field_element_bytes() const
void serialize_xy_to(std::span< uint8_t > bytes) const
static EC_AffinePoint hash_to_curve_nu(const EC_Group &group, std::string_view hash_fn, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep)
bool operator!=(const EC_AffinePoint &other) const
Definition ec_apoint.h:260
bool is_identity() const
Return true if this point is the identity element.
static std::optional< EC_AffinePoint > deserialize_uncompressed(const EC_Group &group, std::span< const uint8_t > bytes)
static EC_AffinePoint identity(const EC_Group &group)
Return the identity element.
Definition ec_apoint.cpp:80
static std::optional< EC_AffinePoint > from_bigint_xy(const EC_Group &group, const BigInt &x, const BigInt &y)
Definition ec_apoint.cpp:93
static std::optional< EC_AffinePoint > mul_px_qy(const EC_AffinePoint &p, const EC_Scalar &x, const EC_AffinePoint &q, const EC_Scalar &y, RandomNumberGenerator &rng)
static EC_AffinePoint g_mul(const EC_Scalar &scalar, RandomNumberGenerator &rng)
Multiply by the group generator returning a complete point.
T serialize_uncompressed() const
Definition ec_apoint.h:232
EC_AffinePoint(const EC_Group &group, std::span< const uint8_t > bytes)
Definition ec_apoint.cpp:36
EC_AffinePoint mul(const EC_Scalar &scalar, RandomNumberGenerator &rng) const
Multiply a point by a scalar returning a complete point.
static std::optional< EC_AffinePoint > deserialize(const EC_Group &group, std::span< const uint8_t > bytes)
static std::optional< EC_AffinePoint > deserialize_compressed(const EC_Group &group, std::span< const uint8_t > bytes)
void serialize_x_to(std::span< uint8_t > bytes) const
T serialize_compressed() const
Definition ec_apoint.h:242
void serialize_compressed_to(std::span< uint8_t > bytes) const
secure_vector< uint8_t > mul_x_only(const EC_Scalar &scalar, RandomNumberGenerator &rng) const
Multiply a point by a scalar, returning the byte encoding of the x coordinate only.
const EC_AffinePoint_Data & _inner() const
Definition ec_apoint.h:337
secure_vector< uint8_t > mul_x_only(const EC_Scalar &scalar, RandomNumberGenerator &rng, std::vector< BigInt > &) const
Multiply a point by a scalar, returning the byte encoding of the x coordinate only.
Definition ec_apoint.h:326
void serialize_uncompressed_to(std::span< uint8_t > bytes) const
void serialize_y_to(std::span< uint8_t > bytes) const
EC_AffinePoint add(const EC_AffinePoint &q) const
friend class EC_Mul2Table
Definition ec_apoint.h:350
static EC_AffinePoint generator(const EC_Group &group)
Return the standard group generator.
Definition ec_apoint.cpp:84
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128
bool operator==(const AlgorithmIdentifier &x, const AlgorithmIdentifier &y)
Definition alg_id.cpp:54