/src/botan/src/lib/pubkey/ec_group/ec_inner_data.cpp
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 | | #include <botan/internal/ec_inner_data.h> |
8 | | |
9 | | #include <botan/der_enc.h> |
10 | | #include <botan/internal/ec_inner_pc.h> |
11 | | #include <botan/internal/fmt.h> |
12 | | #include <botan/internal/pcurves.h> |
13 | | |
14 | | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
15 | | #include <botan/internal/ec_inner_bn.h> |
16 | | #include <botan/internal/point_mul.h> |
17 | | #endif |
18 | | |
19 | | #if defined(BOTAN_HAS_XMD) |
20 | | #include <botan/internal/xmd.h> |
21 | | #endif |
22 | | |
23 | | namespace Botan { |
24 | | |
25 | 2.01k | EC_Group_Data::~EC_Group_Data() = default; |
26 | | |
27 | | // Note this constructor *does not* initialize m_curve, m_base_point or m_base_mult |
28 | | EC_Group_Data::EC_Group_Data(const BigInt& p, |
29 | | const BigInt& a, |
30 | | const BigInt& b, |
31 | | const BigInt& g_x, |
32 | | const BigInt& g_y, |
33 | | const BigInt& order, |
34 | | const BigInt& cofactor, |
35 | | const OID& oid, |
36 | | EC_Group_Source source) : |
37 | 2.01k | m_p(p), |
38 | 2.01k | m_a(a), |
39 | 2.01k | m_b(b), |
40 | 2.01k | m_g_x(g_x), |
41 | 2.01k | m_g_y(g_y), |
42 | 2.01k | m_order(order), |
43 | 2.01k | m_cofactor(cofactor), |
44 | | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
45 | 2.01k | m_mod_field(Modular_Reducer::for_public_modulus(p)), |
46 | 2.01k | m_mod_order(Modular_Reducer::for_public_modulus(order)), |
47 | 2.01k | m_monty(m_p, m_mod_field), |
48 | | #endif |
49 | 2.01k | m_oid(oid), |
50 | 2.01k | m_p_words(p.sig_words()), |
51 | 2.01k | m_p_bits(p.bits()), |
52 | 2.01k | m_order_bits(order.bits()), |
53 | 2.01k | m_order_bytes((m_order_bits + 7) / 8), |
54 | 2.01k | m_a_is_minus_3(a == p - 3), |
55 | 2.01k | m_a_is_zero(a.is_zero()), |
56 | 2.01k | m_has_cofactor(m_cofactor != 1), |
57 | 2.01k | m_order_is_less_than_p(m_order < p), |
58 | 2.01k | m_source(source) { |
59 | | // TODO(Botan4) we can assume/assert the OID is set |
60 | 2.01k | if(!m_oid.empty()) { |
61 | 1.41k | DER_Encoder der(m_der_named_curve); |
62 | 1.41k | der.encode(m_oid); |
63 | | |
64 | 1.41k | const std::string name = m_oid.human_name_or_empty(); |
65 | 1.41k | if(!name.empty()) { |
66 | | // returns nullptr if unknown or not supported |
67 | 1.41k | m_pcurve = PCurve::PrimeOrderCurve::for_named_curve(name); |
68 | 1.41k | } |
69 | 1.41k | if(m_pcurve) { |
70 | 582 | m_engine = EC_Group_Engine::Optimized; |
71 | 582 | } |
72 | 1.41k | } |
73 | | |
74 | | // Try a generic pcurves instance |
75 | 2.01k | if(!m_pcurve && !m_has_cofactor) { |
76 | 1.27k | m_pcurve = PCurve::PrimeOrderCurve::from_params(p, a, b, g_x, g_y, order); |
77 | 1.27k | if(m_pcurve) { |
78 | 404 | m_engine = EC_Group_Engine::Generic; |
79 | 404 | } |
80 | | // possibly still null here, if parameters unsuitable or if the |
81 | | // pcurves_generic module wasn't included in the build |
82 | 1.27k | } |
83 | | |
84 | 2.01k | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
85 | 2.01k | secure_vector<word> ws; |
86 | 2.01k | m_a_r = m_monty.mul(a, m_monty.R2(), ws); |
87 | 2.01k | m_b_r = m_monty.mul(b, m_monty.R2(), ws); |
88 | 2.01k | if(!m_pcurve) { |
89 | 1.02k | m_engine = EC_Group_Engine::Legacy; |
90 | 1.02k | } |
91 | | #else |
92 | | if(!m_pcurve) { |
93 | | if(m_oid.empty()) { |
94 | | throw Not_Implemented("EC_Group this group is not supported in this build configuration"); |
95 | | } else { |
96 | | throw Not_Implemented( |
97 | | fmt("EC_Group the group {} is not supported in this build configuration", oid.to_string())); |
98 | | } |
99 | | } |
100 | | #endif |
101 | 2.01k | } |
102 | | |
103 | | std::shared_ptr<EC_Group_Data> EC_Group_Data::create(const BigInt& p, |
104 | | const BigInt& a, |
105 | | const BigInt& b, |
106 | | const BigInt& g_x, |
107 | | const BigInt& g_y, |
108 | | const BigInt& order, |
109 | | const BigInt& cofactor, |
110 | | const OID& oid, |
111 | 2.01k | EC_Group_Source source) { |
112 | 2.01k | auto group = std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid, source); |
113 | | |
114 | 2.01k | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
115 | 2.01k | group->m_curve = CurveGFp(group.get()); |
116 | 2.01k | group->m_base_point = EC_Point(group->m_curve, g_x, g_y); |
117 | 2.01k | if(!group->m_pcurve) { |
118 | 1.02k | group->m_base_mult = std::make_unique<EC_Point_Base_Point_Precompute>(group->m_base_point, group->m_mod_order); |
119 | 1.02k | } |
120 | 2.01k | #endif |
121 | | |
122 | 2.01k | return group; |
123 | 2.01k | } |
124 | | |
125 | | bool EC_Group_Data::params_match(const BigInt& p, |
126 | | const BigInt& a, |
127 | | const BigInt& b, |
128 | | const BigInt& g_x, |
129 | | const BigInt& g_y, |
130 | | const BigInt& order, |
131 | 55.2k | const BigInt& cofactor) const { |
132 | 55.2k | return (this->p() == p && this->a() == a && this->b() == b && this->order() == order && |
133 | 55.2k | this->cofactor() == cofactor && this->g_x() == g_x && this->g_y() == g_y); |
134 | 55.2k | } |
135 | | |
136 | 0 | bool EC_Group_Data::params_match(const EC_Group_Data& other) const { |
137 | 0 | return params_match(other.p(), other.a(), other.b(), other.g_x(), other.g_y(), other.order(), other.cofactor()); |
138 | 0 | } |
139 | | |
140 | 0 | void EC_Group_Data::set_oid(const OID& oid) { |
141 | 0 | BOTAN_ARG_CHECK(!oid.empty(), "OID should be set"); |
142 | 0 | BOTAN_STATE_CHECK(m_oid.empty() && m_der_named_curve.empty()); |
143 | 0 | m_oid = oid; |
144 | |
|
145 | 0 | DER_Encoder der(m_der_named_curve); |
146 | 0 | der.encode(m_oid); |
147 | 0 | } |
148 | | |
149 | 497 | std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_with_trunc(std::span<const uint8_t> bytes) const { |
150 | 497 | const size_t bit_length = 8 * bytes.size(); |
151 | | |
152 | 497 | if(bit_length < order_bits()) { |
153 | | // No shifting required, but might still need to reduce by modulus |
154 | 187 | return this->scalar_from_bytes_mod_order(bytes); |
155 | 310 | } else { |
156 | 310 | const size_t shift = bit_length - order_bits(); |
157 | | |
158 | 310 | const size_t new_length = bytes.size() - (shift / 8); |
159 | 310 | const size_t bit_shift = shift % 8; |
160 | | |
161 | 310 | if(bit_shift == 0) { |
162 | | // Easy case just read different bytes |
163 | 293 | return this->scalar_from_bytes_mod_order(bytes.first(new_length)); |
164 | 293 | } else { |
165 | 17 | std::vector<uint8_t> sbytes(new_length); |
166 | | |
167 | 17 | uint8_t carry = 0; |
168 | 833 | for(size_t i = 0; i != new_length; ++i) { |
169 | 816 | const uint8_t w = bytes[i]; |
170 | 816 | sbytes[i] = (w >> bit_shift) | carry; |
171 | 816 | carry = w << (8 - bit_shift); |
172 | 816 | } |
173 | | |
174 | 17 | return this->scalar_from_bytes_mod_order(sbytes); |
175 | 17 | } |
176 | 310 | } |
177 | 497 | } |
178 | | |
179 | 978 | std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_mod_order(std::span<const uint8_t> bytes) const { |
180 | 978 | if(bytes.size() > 2 * order_bytes()) { |
181 | 0 | return {}; |
182 | 0 | } |
183 | | |
184 | 978 | if(m_pcurve) { |
185 | 902 | if(auto s = m_pcurve->scalar_from_wide_bytes(bytes)) { |
186 | 902 | return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), std::move(*s)); |
187 | 902 | } else { |
188 | 0 | return {}; |
189 | 0 | } |
190 | 902 | } else { |
191 | 76 | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
192 | 76 | return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(BigInt(bytes))); |
193 | | #else |
194 | | throw Not_Implemented("Legacy EC interfaces disabled in this build configuration"); |
195 | | #endif |
196 | 76 | } |
197 | 978 | } |
198 | | |
199 | 12.8k | std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_random(RandomNumberGenerator& rng) const { |
200 | 12.8k | if(m_pcurve) { |
201 | 12.8k | return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->random_scalar(rng)); |
202 | 12.8k | } else { |
203 | 0 | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
204 | 0 | return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), |
205 | 0 | BigInt::random_integer(rng, BigInt::one(), m_order)); |
206 | | #else |
207 | | throw Not_Implemented("Legacy EC interfaces disabled in this build configuration"); |
208 | | #endif |
209 | 0 | } |
210 | 12.8k | } |
211 | | |
212 | 0 | std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_one() const { |
213 | 0 | if(m_pcurve) { |
214 | 0 | return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_one()); |
215 | 0 | } else { |
216 | 0 | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
217 | 0 | return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::one()); |
218 | | #else |
219 | | throw Not_Implemented("Legacy EC interfaces disabled in this build configuration"); |
220 | | #endif |
221 | 0 | } |
222 | 0 | } |
223 | | |
224 | 0 | std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bigint(const BigInt& bn) const { |
225 | 0 | if(bn <= 0 || bn >= m_order) { |
226 | 0 | return {}; |
227 | 0 | } |
228 | | |
229 | 0 | if(m_pcurve) { |
230 | 0 | return this->scalar_deserialize(bn.serialize(m_order_bytes)); |
231 | 0 | } else { |
232 | 0 | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
233 | 0 | return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), bn); |
234 | | #else |
235 | | throw Not_Implemented("Legacy EC interfaces disabled in this build configuration"); |
236 | | #endif |
237 | 0 | } |
238 | 0 | } |
239 | | |
240 | | std::unique_ptr<EC_Scalar_Data> EC_Group_Data::gk_x_mod_order(const EC_Scalar_Data& scalar, |
241 | 0 | RandomNumberGenerator& rng) const { |
242 | 0 | if(m_pcurve) { |
243 | 0 | const auto& k = EC_Scalar_Data_PC::checked_ref(scalar); |
244 | 0 | auto gk_x_mod_order = m_pcurve->base_point_mul_x_mod_order(k.value(), rng); |
245 | 0 | return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), gk_x_mod_order); |
246 | 0 | } else { |
247 | 0 | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
248 | 0 | const auto& k = EC_Scalar_Data_BN::checked_ref(scalar); |
249 | 0 | BOTAN_STATE_CHECK(m_base_mult != nullptr); |
250 | 0 | std::vector<BigInt> ws; |
251 | 0 | const auto pt = m_base_mult->mul(k.value(), rng, m_order, ws); |
252 | |
|
253 | 0 | if(pt.is_zero()) { |
254 | 0 | return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::zero()); |
255 | 0 | } else { |
256 | 0 | return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), m_mod_order.reduce(pt.get_affine_x())); |
257 | 0 | } |
258 | | #else |
259 | | throw Not_Implemented("Legacy EC interfaces disabled in this build configuration"); |
260 | | #endif |
261 | 0 | } |
262 | 0 | } |
263 | | |
264 | 9.57k | std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_deserialize(std::span<const uint8_t> bytes) const { |
265 | 9.57k | if(bytes.size() != m_order_bytes) { |
266 | 288 | return nullptr; |
267 | 288 | } |
268 | | |
269 | 9.28k | if(m_pcurve) { |
270 | 8.67k | if(auto s = m_pcurve->deserialize_scalar(bytes)) { |
271 | 8.57k | return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), *s); |
272 | 8.57k | } else { |
273 | 102 | return nullptr; |
274 | 102 | } |
275 | 8.67k | } else { |
276 | 604 | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
277 | 604 | BigInt r(bytes); |
278 | | |
279 | 604 | if(r.is_zero() || r >= m_order) { |
280 | 24 | return nullptr; |
281 | 24 | } |
282 | | |
283 | 580 | return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), std::move(r)); |
284 | | #else |
285 | | throw Not_Implemented("Legacy EC interfaces disabled in this build configuration"); |
286 | | #endif |
287 | 604 | } |
288 | 9.28k | } |
289 | | |
290 | 15.1k | std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_deserialize(std::span<const uint8_t> bytes) const { |
291 | | // The deprecated "hybrid" point format |
292 | | // TODO(Botan4) remove this |
293 | 15.1k | if(bytes.size() >= 1 + 2 * 4 && (bytes[0] == 0x06 || bytes[0] == 0x07)) { |
294 | 688 | bool hdr_y_is_even = bytes[0] == 0x06; |
295 | 688 | bool y_is_even = (bytes.back() & 0x01) == 0; |
296 | | |
297 | 688 | if(hdr_y_is_even == y_is_even) { |
298 | 431 | std::vector<uint8_t> sec1(bytes.begin(), bytes.end()); |
299 | 431 | sec1[0] = 0x04; |
300 | 431 | return this->point_deserialize(sec1); |
301 | 431 | } |
302 | 688 | } |
303 | | |
304 | 14.6k | try { |
305 | 14.6k | if(m_pcurve) { |
306 | 13.9k | if(auto pt = m_pcurve->deserialize_point(bytes)) { |
307 | 11.3k | return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(*pt)); |
308 | 11.3k | } else { |
309 | 2.59k | return {}; |
310 | 2.59k | } |
311 | 13.9k | } else { |
312 | 708 | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
313 | 708 | auto pt = Botan::OS2ECP(bytes, m_curve); |
314 | 708 | return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt)); |
315 | | #else |
316 | | throw Not_Implemented("Legacy EC interfaces disabled in this build configuration"); |
317 | | #endif |
318 | 708 | } |
319 | 14.6k | } catch(...) { |
320 | 447 | return {}; |
321 | 447 | } |
322 | 14.6k | } |
323 | | |
324 | | namespace { |
325 | | |
326 | | std::function<void(std::span<uint8_t>)> h2c_expand_message(std::string_view hash_fn, |
327 | | std::span<const uint8_t> input, |
328 | 0 | std::span<const uint8_t> domain_sep) { |
329 | | /* |
330 | | * This could be extended to support expand_message_xof or a MHF like Argon2 |
331 | | */ |
332 | |
|
333 | 0 | if(hash_fn.starts_with("SHAKE")) { |
334 | 0 | throw Not_Implemented("Hash to curve currently does not support expand_message_xof"); |
335 | 0 | } |
336 | | |
337 | 0 | return [=](std::span<uint8_t> uniform_bytes) { |
338 | 0 | #if defined(BOTAN_HAS_XMD) |
339 | 0 | expand_message_xmd(hash_fn, uniform_bytes, input, domain_sep); |
340 | | #else |
341 | | BOTAN_UNUSED(hash_fn, uniform_bytes, input, domain_sep); |
342 | | throw Not_Implemented("Hash to curve is not implemented due to XMD being disabled"); |
343 | | #endif |
344 | 0 | }; |
345 | 0 | } |
346 | | |
347 | | } // namespace |
348 | | |
349 | | std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_ro(std::string_view hash_fn, |
350 | | std::span<const uint8_t> input, |
351 | 0 | std::span<const uint8_t> domain_sep) const { |
352 | 0 | if(m_pcurve) { |
353 | 0 | auto pt = m_pcurve->hash_to_curve_ro(h2c_expand_message(hash_fn, input, domain_sep)); |
354 | 0 | return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(pt)); |
355 | 0 | } else { |
356 | 0 | throw Not_Implemented("Hash to curve is not implemented for this curve"); |
357 | 0 | } |
358 | 0 | } |
359 | | |
360 | | std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_nu(std::string_view hash_fn, |
361 | | std::span<const uint8_t> input, |
362 | 0 | std::span<const uint8_t> domain_sep) const { |
363 | 0 | if(m_pcurve) { |
364 | 0 | auto pt = m_pcurve->hash_to_curve_nu(h2c_expand_message(hash_fn, input, domain_sep)); |
365 | 0 | return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt)); |
366 | 0 | } else { |
367 | 0 | throw Not_Implemented("Hash to curve is not implemented for this curve"); |
368 | 0 | } |
369 | 0 | } |
370 | | |
371 | | std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_g_mul(const EC_Scalar_Data& scalar, |
372 | 13.4k | RandomNumberGenerator& rng) const { |
373 | 13.4k | if(m_pcurve) { |
374 | 13.3k | const auto& k = EC_Scalar_Data_PC::checked_ref(scalar); |
375 | 13.3k | auto pt = m_pcurve->point_to_affine(m_pcurve->mul_by_g(k.value(), rng)); |
376 | 13.3k | return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt)); |
377 | 13.3k | } else { |
378 | 80 | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
379 | 80 | const auto& group = scalar.group(); |
380 | 80 | const auto& bn = EC_Scalar_Data_BN::checked_ref(scalar); |
381 | | |
382 | 80 | BOTAN_STATE_CHECK(group->m_base_mult != nullptr); |
383 | 80 | std::vector<BigInt> ws; |
384 | 80 | auto pt = group->m_base_mult->mul(bn.value(), rng, m_order, ws); |
385 | 80 | return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt)); |
386 | | #else |
387 | | throw Not_Implemented("Legacy EC interfaces disabled in this build configuration"); |
388 | | #endif |
389 | 80 | } |
390 | 13.4k | } |
391 | | |
392 | | std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::mul_px_qy(const EC_AffinePoint_Data& p, |
393 | | const EC_Scalar_Data& x, |
394 | | const EC_AffinePoint_Data& q, |
395 | | const EC_Scalar_Data& y, |
396 | 0 | RandomNumberGenerator& rng) const { |
397 | 0 | if(m_pcurve) { |
398 | 0 | auto pt = m_pcurve->mul_px_qy(EC_AffinePoint_Data_PC::checked_ref(p).value(), |
399 | 0 | EC_Scalar_Data_PC::checked_ref(x).value(), |
400 | 0 | EC_AffinePoint_Data_PC::checked_ref(q).value(), |
401 | 0 | EC_Scalar_Data_PC::checked_ref(y).value(), |
402 | 0 | rng); |
403 | |
|
404 | 0 | if(pt) { |
405 | 0 | return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(*pt)); |
406 | 0 | } else { |
407 | 0 | return nullptr; |
408 | 0 | } |
409 | 0 | } else { |
410 | 0 | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
411 | 0 | std::vector<BigInt> ws; |
412 | 0 | const auto& group = p.group(); |
413 | | |
414 | | // TODO this could be better! |
415 | 0 | EC_Point_Var_Point_Precompute p_mul(p.to_legacy_point(), rng, ws); |
416 | 0 | EC_Point_Var_Point_Precompute q_mul(q.to_legacy_point(), rng, ws); |
417 | |
|
418 | 0 | const auto order = group->order() * group->cofactor(); // See #3800 |
419 | |
|
420 | 0 | auto px = p_mul.mul(EC_Scalar_Data_BN::checked_ref(x).value(), rng, order, ws); |
421 | 0 | auto qy = q_mul.mul(EC_Scalar_Data_BN::checked_ref(y).value(), rng, order, ws); |
422 | |
|
423 | 0 | auto px_qy = px + qy; |
424 | |
|
425 | 0 | if(!px_qy.is_zero()) { |
426 | 0 | px_qy.force_affine(); |
427 | 0 | return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(px_qy)); |
428 | 0 | } else { |
429 | 0 | return nullptr; |
430 | 0 | } |
431 | | #else |
432 | | throw Not_Implemented("Legacy EC interfaces disabled in this build configuration"); |
433 | | #endif |
434 | 0 | } |
435 | 0 | } |
436 | | |
437 | | std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::affine_add(const EC_AffinePoint_Data& p, |
438 | 680 | const EC_AffinePoint_Data& q) const { |
439 | 680 | if(m_pcurve) { |
440 | 680 | auto pt = m_pcurve->point_add(EC_AffinePoint_Data_PC::checked_ref(p).value(), |
441 | 680 | EC_AffinePoint_Data_PC::checked_ref(q).value()); |
442 | | |
443 | 680 | return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), m_pcurve->point_to_affine(pt)); |
444 | 680 | } else { |
445 | 0 | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
446 | 0 | auto pt = p.to_legacy_point() + q.to_legacy_point(); |
447 | 0 | return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt)); |
448 | | #else |
449 | | throw Not_Implemented("Legacy EC interfaces disabled in this build configuration"); |
450 | | #endif |
451 | 0 | } |
452 | 680 | } |
453 | | |
454 | 0 | std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::affine_neg(const EC_AffinePoint_Data& p) const { |
455 | 0 | if(m_pcurve) { |
456 | 0 | auto pt = m_pcurve->point_negate(EC_AffinePoint_Data_PC::checked_ref(p).value()); |
457 | 0 | return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt); |
458 | 0 | } else { |
459 | 0 | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
460 | 0 | auto pt = p.to_legacy_point(); |
461 | 0 | pt.negate(); // negates in place |
462 | 0 | return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt)); |
463 | | #else |
464 | | throw Not_Implemented("Legacy EC interfaces disabled in this build configuration"); |
465 | | #endif |
466 | 0 | } |
467 | 0 | } |
468 | | |
469 | 821 | std::unique_ptr<EC_Mul2Table_Data> EC_Group_Data::make_mul2_table(const EC_AffinePoint_Data& h) const { |
470 | 821 | if(m_pcurve) { |
471 | 730 | return std::make_unique<EC_Mul2Table_Data_PC>(h); |
472 | 730 | } else { |
473 | 91 | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
474 | 91 | EC_AffinePoint_Data_BN g(shared_from_this(), this->base_point()); |
475 | 91 | return std::make_unique<EC_Mul2Table_Data_BN>(g, h); |
476 | | #else |
477 | | throw Not_Implemented("Legacy EC interfaces disabled in this build configuration"); |
478 | | #endif |
479 | 91 | } |
480 | 821 | } |
481 | | |
482 | | } // namespace Botan |