Botan 3.13.0
Crypto and TLS for C&
ec_inner_data.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_INNER_DATA_H_
8#define BOTAN_EC_INNER_DATA_H_
9
10#include <botan/ec_group.h>
11
12#include <botan/asn1_obj.h>
13#include <botan/bigint.h>
14#include <botan/internal/monty.h>
15#include <functional>
16#include <memory>
17#include <span>
18
19#if defined(BOTAN_HAS_LEGACY_EC_POINT)
20 #include <botan/internal/barrett.h>
21#endif
22
23namespace Botan {
24
25#if defined(BOTAN_HAS_LEGACY_EC_POINT)
27#endif
28
29namespace PCurve {
30
31class PrimeOrderCurve;
32
33}
34
35class EC_Group_Data;
36
37class EC_Scalar_Data /* NOLINT(*-special-member-functions) */ {
38 public:
39 virtual ~EC_Scalar_Data() = default;
40
41 virtual const std::shared_ptr<const EC_Group_Data>& group() const = 0;
42
43 virtual size_t bytes() const = 0;
44
45 virtual std::unique_ptr<EC_Scalar_Data> clone() const = 0;
46
47 virtual bool is_zero() const = 0;
48
49 virtual bool is_eq(const EC_Scalar_Data& y) const = 0;
50
51 virtual void assign(const EC_Scalar_Data& y) = 0;
52
53 virtual void zeroize() = 0;
54
55 virtual void square_self() = 0;
56
57 virtual std::unique_ptr<EC_Scalar_Data> negate() const = 0;
58
59 virtual std::unique_ptr<EC_Scalar_Data> invert() const = 0;
60
61 virtual std::unique_ptr<EC_Scalar_Data> invert_vartime() const = 0;
62
63 virtual std::unique_ptr<EC_Scalar_Data> add(const EC_Scalar_Data& other) const = 0;
64
65 virtual std::unique_ptr<EC_Scalar_Data> sub(const EC_Scalar_Data& other) const = 0;
66
67 virtual std::unique_ptr<EC_Scalar_Data> mul(const EC_Scalar_Data& other) const = 0;
68
69 virtual void serialize_to(std::span<uint8_t> bytes) const = 0;
70};
71
72class EC_AffinePoint_Data /* NOLINT(*-special-member-functions) */ {
73 public:
74 virtual ~EC_AffinePoint_Data() = default;
75
76 virtual const std::shared_ptr<const EC_Group_Data>& group() const = 0;
77
78 virtual std::unique_ptr<EC_AffinePoint_Data> clone() const = 0;
79
80 // Return size of a field element
81 virtual size_t field_element_bytes() const = 0;
82
83 // Return if this is the identity element
84 virtual bool is_identity() const = 0;
85
86 // Writes 1 field element worth of data to bytes
87 virtual void serialize_x_to(std::span<uint8_t> bytes) const = 0;
88
89 // Writes 1 field element worth of data to bytes
90 virtual void serialize_y_to(std::span<uint8_t> bytes) const = 0;
91
92 // Writes 2 field elements worth of data to bytes
93 virtual void serialize_xy_to(std::span<uint8_t> bytes) const = 0;
94
95 // Writes 1 byte + 1 field element worth of data to bytes
96 virtual void serialize_compressed_to(std::span<uint8_t> bytes) const = 0;
97
98 // Writes 1 byte + 2 field elements worth of data to bytes
99 virtual void serialize_uncompressed_to(std::span<uint8_t> bytes) const = 0;
100
101 virtual std::unique_ptr<EC_AffinePoint_Data> mul(const EC_Scalar_Data& scalar,
102 RandomNumberGenerator& rng) const = 0;
103
105
106#if defined(BOTAN_HAS_LEGACY_EC_POINT)
107 virtual EC_Point to_legacy_point() const = 0;
108#endif
109};
110
111class EC_Mul2Table_Data /* NOLINT(*-special-member-functions) */ {
112 public:
113 virtual ~EC_Mul2Table_Data() = default;
114
115 // Returns nullptr if g*x + h*y was point at infinity
116 virtual std::unique_ptr<EC_AffinePoint_Data> mul2_vartime(const EC_Scalar_Data& x,
117 const EC_Scalar_Data& y) const = 0;
118
119 // Check if v == (g*x + h*y).x % n
120 //
121 // Returns false if g*x + h*y was point at infinity
123 const EC_Scalar_Data& x,
124 const EC_Scalar_Data& y) const = 0;
125};
126
127class EC_Group_Data final : public std::enable_shared_from_this<EC_Group_Data> {
128 public:
129 static std::shared_ptr<EC_Group_Data> create(const BigInt& p,
130 const BigInt& a,
131 const BigInt& b,
132 const BigInt& g_x,
133 const BigInt& g_y,
134 const BigInt& order,
135 const BigInt& cofactor,
136 const OID& oid,
138
140
141 EC_Group_Data(const EC_Group_Data& other) = delete;
142 EC_Group_Data(EC_Group_Data&& other) = delete;
143 EC_Group_Data& operator=(const EC_Group_Data& other) = delete;
145
146 bool params_match(const BigInt& p,
147 const BigInt& a,
148 const BigInt& b,
149 const BigInt& g_x,
150 const BigInt& g_y,
151 const BigInt& order,
152 const BigInt& cofactor) const;
153
154 // Like the other params_match but accepting the base point in encoded form
155 bool params_match(const BigInt& p,
156 const BigInt& a,
157 const BigInt& b,
158 std::span<const uint8_t> base_pt,
159 const BigInt& order,
160 const BigInt& cofactor) const;
161
162 bool params_match(const EC_Group_Data& other) const;
163
164 void set_oid(const OID& oid);
165
166 const OID& oid() const { return m_oid; }
167
168 const std::vector<uint8_t>& der_named_curve() const { return m_der_named_curve; }
169
170 const BigInt& p() const { return m_p; }
171
172 const BigInt& a() const { return m_a; }
173
174 const BigInt& b() const { return m_b; }
175
176 const BigInt& order() const { return m_order; }
177
178 const BigInt& cofactor() const { return m_cofactor; }
179
180#if defined(BOTAN_HAS_LEGACY_EC_POINT)
181 const CurveGFp& curve() const { return m_curve; }
182
183 const EC_Point& base_point() const { return m_base_point; }
184
185 const Montgomery_Params& monty() const { return m_monty; }
186
187 const BigInt& monty_a() const { return m_a_r; }
188
189 const BigInt& monty_b() const { return m_b_r; }
190
191 const Barrett_Reduction& mod_order() const { return m_mod_order; }
192#endif
193
194 bool order_is_less_than_p() const { return m_order_is_less_than_p; }
195
196 bool has_cofactor() const { return m_has_cofactor; }
197
198 const BigInt& g_x() const { return m_g_x; }
199
200 const BigInt& g_y() const { return m_g_y; }
201
202 size_t p_words() const { return m_p_words; }
203
204 size_t p_bits() const { return m_p_bits; }
205
206 size_t p_bytes() const { return (m_p_bits + 7) / 8; }
207
208 size_t order_bits() const { return m_order_bits; }
209
210 size_t order_bytes() const { return m_order_bytes; }
211
212 bool a_is_minus_3() const { return m_a_is_minus_3; }
213
214 bool a_is_zero() const { return m_a_is_zero; }
215
216 EC_Group_Source source() const { return m_source; }
217
218 EC_Group_Engine engine() const { return m_engine; }
219
220 /// Scalar from bytes
221 ///
222 /// This returns a value only if the bytes represent (in big-endian encoding) an integer
223 /// that is less than n, where n is the group order. It requires that the fixed length
224 /// encoding (with zero prefix) be used. It also rejects inputs that encode zero.
225 /// Thus the accepted range is [1,n)
226 ///
227 /// If the input is rejected then nullptr is returned
228 std::unique_ptr<EC_Scalar_Data> scalar_deserialize(std::span<const uint8_t> bytes) const;
229
230 /// Scalar from bytes with ECDSA style truncation
231 ///
232 /// This should always succeed
233 std::unique_ptr<EC_Scalar_Data> scalar_from_bytes_with_trunc(std::span<const uint8_t> bytes) const;
234
235 /// Scalar from bytes with modular reduction
236 ///
237 /// This returns a value only if bytes represents (in big-endian encoding) an integer
238 /// that is at most the square of the scalar group size. Otherwise it returns nullptr.
239 std::unique_ptr<EC_Scalar_Data> scalar_from_bytes_mod_order(std::span<const uint8_t> bytes) const;
240
241 /// Scalar from BigInt
242 ///
243 /// This returns a value only if bn is in [1,n) where n is the group order.
244 /// Otherwise it returns nullptr
245 std::unique_ptr<EC_Scalar_Data> scalar_from_bigint(const BigInt& bn) const;
246
247 /// Return a random scalar
248 ///
249 /// This will be in the range [1,n) where n is the group order
250 std::unique_ptr<EC_Scalar_Data> scalar_random(RandomNumberGenerator& rng) const;
251
252 std::unique_ptr<EC_Scalar_Data> scalar_one() const;
253
254 std::unique_ptr<EC_Scalar_Data> gk_x_mod_order(const EC_Scalar_Data& scalar, RandomNumberGenerator& rng) const;
255
256 /// Deserialize a point in the SEC1 uncompressed format
257 ///
258 /// Returns nullptr if the encoding was not in the uncompressed format,
259 /// or if the point is not on the curve
260 std::unique_ptr<EC_AffinePoint_Data> point_deserialize_uncompressed(std::span<const uint8_t> bytes) const;
261
262 /// Deserialize a point in the SEC1 compressed format
263 ///
264 /// Returns nullptr if the encoding was not in the compressed format,
265 /// or if the point is not on the curve
266 std::unique_ptr<EC_AffinePoint_Data> point_deserialize_compressed(std::span<const uint8_t> bytes) const;
267
268 /// Return the identity element (aka the point at infinity)
269 std::unique_ptr<EC_AffinePoint_Data> point_identity() const;
270
271 /// Return true if point_hash_to_curve_ro/point_hash_to_curve_nu will
272 /// work for this group when using the specified hash function
273 bool hash_to_curve_supported(std::string_view hash_fn) const;
274
275 std::unique_ptr<EC_AffinePoint_Data> point_hash_to_curve_ro(std::string_view hash_fn,
276 std::span<const uint8_t> input,
277 std::span<const uint8_t> domain_sep) const;
278
279 std::unique_ptr<EC_AffinePoint_Data> point_hash_to_curve_nu(std::string_view hash_fn,
280 std::span<const uint8_t> input,
281 std::span<const uint8_t> domain_sep) const;
282
283 std::unique_ptr<EC_AffinePoint_Data> point_g_mul(const EC_Scalar_Data& scalar, RandomNumberGenerator& rng) const;
284
285 std::unique_ptr<EC_AffinePoint_Data> mul_px_qy(const EC_AffinePoint_Data& p,
286 const EC_Scalar_Data& x,
287 const EC_AffinePoint_Data& q,
288 const EC_Scalar_Data& y,
289 RandomNumberGenerator& rng) const;
290
291 std::unique_ptr<EC_AffinePoint_Data> affine_add(const EC_AffinePoint_Data& p, const EC_AffinePoint_Data& q) const;
292
293 std::unique_ptr<EC_AffinePoint_Data> affine_neg(const EC_AffinePoint_Data& p) const;
294
295 std::unique_ptr<EC_Mul2Table_Data> make_mul2_table(const EC_AffinePoint_Data& pt) const;
296
298 BOTAN_ASSERT_NONNULL(m_pcurve);
299 return *m_pcurve;
300 }
301
302 /**
303 * Note this constructor should *only* be called by EC_Group_Data::create.
304 *
305 * It is only public to allow use of std::make_shared
306 */
307 EC_Group_Data(const BigInt& p,
308 const BigInt& a,
309 const BigInt& b,
310 const BigInt& g_x,
311 const BigInt& g_y,
312 const BigInt& order,
313 const BigInt& cofactor,
314 const OID& oid,
316
317 private:
318 // Possibly nullptr (if pcurves not available or not a standard curve)
319 std::shared_ptr<const PCurve::PrimeOrderCurve> m_pcurve;
320
321#if defined(BOTAN_HAS_LEGACY_EC_POINT)
322 // Set only if m_pcurve is nullptr
323 std::unique_ptr<EC_Point_Base_Point_Precompute> m_base_mult;
324#endif
325
326 BigInt m_p;
327 BigInt m_a;
328 BigInt m_b;
329 BigInt m_g_x;
330 BigInt m_g_y;
331 BigInt m_order;
332 BigInt m_cofactor;
333
334#if defined(BOTAN_HAS_LEGACY_EC_POINT)
335 CurveGFp m_curve;
336 EC_Point m_base_point;
337
338 Barrett_Reduction m_mod_field;
339 Barrett_Reduction m_mod_order;
340
341 // Montgomery parameters (only used for legacy EC_Point)
342 Montgomery_Params m_monty;
343
344 BigInt m_a_r; // (a*r) % p
345 BigInt m_b_r; // (b*r) % p
346#endif
347
348 OID m_oid;
349 std::vector<uint8_t> m_der_named_curve;
350 size_t m_p_words;
351 size_t m_p_bits;
352 size_t m_order_bits;
353 size_t m_order_bytes;
354 bool m_a_is_minus_3;
355 bool m_a_is_zero;
356 bool m_has_cofactor;
357 bool m_order_is_less_than_p;
358 EC_Group_Source m_source;
359 EC_Group_Engine m_engine;
360};
361
362/**
363* Instantiate the named hash and return a closure implementing the
364* expand_message function of RFC 9380
365*
366* Throws if the hash is unknown, or too weak for use with a group
367* of order_bits, per the RFC 9380 requirements
368*/
369std::function<void(std::span<uint8_t>)> h2c_expand_message(std::string_view hash_fn,
370 size_t order_bits,
371 std::span<const uint8_t> input,
372 std::span<const uint8_t> domain_sep);
373
374} // namespace Botan
375
376#endif
#define BOTAN_ASSERT_NONNULL(ptr)
Definition assert.h:114
virtual void serialize_compressed_to(std::span< uint8_t > bytes) const =0
virtual ~EC_AffinePoint_Data()=default
virtual std::unique_ptr< EC_AffinePoint_Data > mul(const EC_Scalar_Data &scalar, RandomNumberGenerator &rng) const =0
virtual secure_vector< uint8_t > mul_x_only(const EC_Scalar_Data &scalar, RandomNumberGenerator &rng) const =0
virtual void serialize_y_to(std::span< uint8_t > bytes) const =0
virtual std::unique_ptr< EC_AffinePoint_Data > clone() const =0
virtual size_t field_element_bytes() const =0
virtual void serialize_uncompressed_to(std::span< uint8_t > bytes) const =0
virtual void serialize_x_to(std::span< uint8_t > bytes) const =0
virtual const std::shared_ptr< const EC_Group_Data > & group() const =0
virtual bool is_identity() const =0
virtual void serialize_xy_to(std::span< uint8_t > bytes) const =0
std::unique_ptr< EC_Scalar_Data > gk_x_mod_order(const EC_Scalar_Data &scalar, RandomNumberGenerator &rng) const
const BigInt & p() const
const BigInt & g_x() const
std::unique_ptr< EC_AffinePoint_Data > affine_neg(const EC_AffinePoint_Data &p) const
const BigInt & a() const
std::unique_ptr< EC_Scalar_Data > scalar_from_bytes_mod_order(std::span< const uint8_t > bytes) const
bool a_is_minus_3() const
std::unique_ptr< EC_Scalar_Data > scalar_random(RandomNumberGenerator &rng) const
bool has_cofactor() const
std::unique_ptr< EC_Scalar_Data > scalar_deserialize(std::span< const uint8_t > bytes) const
bool params_match(const BigInt &p, const BigInt &a, const BigInt &b, const BigInt &g_x, const BigInt &g_y, const BigInt &order, const BigInt &cofactor) const
const PCurve::PrimeOrderCurve & pcurve() const
static std::shared_ptr< EC_Group_Data > create(const BigInt &p, const BigInt &a, const BigInt &b, const BigInt &g_x, const BigInt &g_y, const BigInt &order, const BigInt &cofactor, const OID &oid, EC_Group_Source source)
EC_Group_Data & operator=(EC_Group_Data &&other)=delete
std::unique_ptr< EC_AffinePoint_Data > affine_add(const EC_AffinePoint_Data &p, const EC_AffinePoint_Data &q) const
std::unique_ptr< EC_Scalar_Data > scalar_from_bytes_with_trunc(std::span< const uint8_t > bytes) const
std::unique_ptr< EC_Mul2Table_Data > make_mul2_table(const EC_AffinePoint_Data &pt) const
std::unique_ptr< EC_AffinePoint_Data > mul_px_qy(const EC_AffinePoint_Data &p, const EC_Scalar_Data &x, const EC_AffinePoint_Data &q, const EC_Scalar_Data &y, RandomNumberGenerator &rng) const
std::unique_ptr< EC_AffinePoint_Data > point_deserialize_compressed(std::span< const uint8_t > bytes) const
std::unique_ptr< EC_Scalar_Data > scalar_one() const
const OID & oid() const
EC_Group_Data & operator=(const EC_Group_Data &other)=delete
std::unique_ptr< EC_AffinePoint_Data > point_g_mul(const EC_Scalar_Data &scalar, RandomNumberGenerator &rng) const
size_t order_bits() const
const BigInt & cofactor() const
std::unique_ptr< EC_AffinePoint_Data > point_identity() const
Return the identity element (aka the point at infinity).
std::unique_ptr< EC_AffinePoint_Data > point_deserialize_uncompressed(std::span< const uint8_t > bytes) const
const std::vector< uint8_t > & der_named_curve() const
bool order_is_less_than_p() const
EC_Group_Data(EC_Group_Data &&other)=delete
EC_Group_Data(const EC_Group_Data &other)=delete
size_t p_words() const
size_t p_bytes() const
EC_Group_Source source() const
void set_oid(const OID &oid)
EC_Group_Engine engine() const
bool hash_to_curve_supported(std::string_view hash_fn) const
const BigInt & g_y() const
size_t order_bytes() const
std::unique_ptr< EC_Scalar_Data > scalar_from_bigint(const BigInt &bn) const
std::unique_ptr< EC_AffinePoint_Data > point_hash_to_curve_ro(std::string_view hash_fn, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep) const
size_t p_bits() const
const BigInt & b() const
std::unique_ptr< EC_AffinePoint_Data > point_hash_to_curve_nu(std::string_view hash_fn, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep) const
const BigInt & order() const
virtual ~EC_Mul2Table_Data()=default
virtual bool mul2_vartime_x_mod_order_eq(const EC_Scalar_Data &v, const EC_Scalar_Data &x, const EC_Scalar_Data &y) const =0
virtual std::unique_ptr< EC_AffinePoint_Data > mul2_vartime(const EC_Scalar_Data &x, const EC_Scalar_Data &y) const =0
virtual void assign(const EC_Scalar_Data &y)=0
virtual const std::shared_ptr< const EC_Group_Data > & group() const =0
virtual std::unique_ptr< EC_Scalar_Data > invert_vartime() const =0
virtual void zeroize()=0
virtual size_t bytes() const =0
virtual std::unique_ptr< EC_Scalar_Data > sub(const EC_Scalar_Data &other) const =0
virtual std::unique_ptr< EC_Scalar_Data > invert() const =0
virtual void serialize_to(std::span< uint8_t > bytes) const =0
virtual std::unique_ptr< EC_Scalar_Data > negate() const =0
virtual std::unique_ptr< EC_Scalar_Data > clone() const =0
virtual std::unique_ptr< EC_Scalar_Data > add(const EC_Scalar_Data &other) const =0
virtual void square_self()=0
virtual bool is_eq(const EC_Scalar_Data &y) const =0
virtual bool is_zero() const =0
virtual ~EC_Scalar_Data()=default
virtual std::unique_ptr< EC_Scalar_Data > mul(const EC_Scalar_Data &other) const =0
std::function< void(std::span< uint8_t >)> h2c_expand_message(std::string_view hash_fn, size_t order_bits, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep)
EC_Group_Engine
Definition ec_group.h:48
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128
EC_Group_Source
Definition ec_group.h:38