/src/botan/src/lib/pubkey/ec_group/ec_group.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * ECC Domain Parameters |
3 | | * |
4 | | * (C) 2007 Falko Strenzke, FlexSecure GmbH |
5 | | * (C) 2008,2018 Jack Lloyd |
6 | | * (C) 2018 Tobias Niemann |
7 | | * |
8 | | * Botan is released under the Simplified BSD License (see license.txt) |
9 | | */ |
10 | | |
11 | | #include <botan/ec_group.h> |
12 | | #include <botan/internal/point_mul.h> |
13 | | #include <botan/internal/primality.h> |
14 | | #include <botan/ber_dec.h> |
15 | | #include <botan/der_enc.h> |
16 | | #include <botan/pem.h> |
17 | | #include <botan/reducer.h> |
18 | | #include <botan/mutex.h> |
19 | | #include <botan/rng.h> |
20 | | #include <vector> |
21 | | |
22 | | namespace Botan { |
23 | | |
24 | | class EC_Group_Data final |
25 | | { |
26 | | public: |
27 | | |
28 | | 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 | | m_curve(p, a, b), |
37 | | m_base_point(m_curve, g_x, g_y), |
38 | | m_g_x(g_x), |
39 | | m_g_y(g_y), |
40 | | m_order(order), |
41 | | m_cofactor(cofactor), |
42 | | m_mod_order(order), |
43 | | m_base_mult(m_base_point, m_mod_order), |
44 | | m_oid(oid), |
45 | | m_p_bits(p.bits()), |
46 | | m_order_bits(order.bits()), |
47 | | m_a_is_minus_3(a == p - 3), |
48 | | m_a_is_zero(a.is_zero()) |
49 | 1.21k | { |
50 | 1.21k | } |
51 | | |
52 | | bool match(const BigInt& p, const BigInt& a, const BigInt& b, |
53 | | const BigInt& g_x, const BigInt& g_y, |
54 | | const BigInt& order, const BigInt& cofactor) const |
55 | 0 | { |
56 | 0 | return (this->p() == p && |
57 | 0 | this->a() == a && |
58 | 0 | this->b() == b && |
59 | 0 | this->order() == order && |
60 | 0 | this->cofactor() == cofactor && |
61 | 0 | this->g_x() == g_x && |
62 | 0 | this->g_y() == g_y); |
63 | 0 | } |
64 | | |
65 | | void set_oid(const OID& oid) |
66 | 0 | { |
67 | 0 | BOTAN_STATE_CHECK(m_oid.empty()); |
68 | 0 | m_oid = oid; |
69 | 0 | } |
70 | | |
71 | 68.8k | const OID& oid() const { return m_oid; } |
72 | 2.59k | const BigInt& p() const { return m_curve.get_p(); } |
73 | 2.59k | const BigInt& a() const { return m_curve.get_a(); } |
74 | 2.59k | const BigInt& b() const { return m_curve.get_b(); } |
75 | 37.2k | const BigInt& order() const { return m_order; } |
76 | 21.0k | const BigInt& cofactor() const { return m_cofactor; } |
77 | 0 | const BigInt& g_x() const { return m_g_x; } |
78 | 0 | const BigInt& g_y() const { return m_g_y; } |
79 | | |
80 | 332 | size_t p_bits() const { return m_p_bits; } |
81 | 8.95k | size_t p_bytes() const { return (m_p_bits + 7) / 8; } |
82 | | |
83 | 746 | size_t order_bits() const { return m_order_bits; } |
84 | 373 | size_t order_bytes() const { return (m_order_bits + 7) / 8; } |
85 | | |
86 | 22.8k | const CurveGFp& curve() const { return m_curve; } |
87 | 1.41k | const PointGFp& base_point() const { return m_base_point; } |
88 | | |
89 | 0 | bool a_is_minus_3() const { return m_a_is_minus_3; } |
90 | 0 | bool a_is_zero() const { return m_a_is_zero; } |
91 | | |
92 | 708 | BigInt mod_order(const BigInt& x) const { return m_mod_order.reduce(x); } |
93 | | |
94 | | BigInt square_mod_order(const BigInt& x) const |
95 | 0 | { |
96 | 0 | return m_mod_order.square(x); |
97 | 0 | } |
98 | | |
99 | | BigInt multiply_mod_order(const BigInt& x, const BigInt& y) const |
100 | 726 | { |
101 | 726 | return m_mod_order.multiply(x, y); |
102 | 726 | } |
103 | | |
104 | | BigInt multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const |
105 | 0 | { |
106 | 0 | return m_mod_order.multiply(m_mod_order.multiply(x, y), z); |
107 | 0 | } |
108 | | |
109 | | BigInt inverse_mod_order(const BigInt& x) const |
110 | 10.9k | { |
111 | 10.9k | return inverse_mod(x, m_order); |
112 | 10.9k | } |
113 | | |
114 | | PointGFp blinded_base_point_multiply(const BigInt& k, |
115 | | RandomNumberGenerator& rng, |
116 | | std::vector<BigInt>& ws) const |
117 | 23.7k | { |
118 | 23.7k | return m_base_mult.mul(k, rng, m_order, ws); |
119 | 23.7k | } |
120 | | |
121 | | private: |
122 | | CurveGFp m_curve; |
123 | | PointGFp m_base_point; |
124 | | |
125 | | BigInt m_g_x; |
126 | | BigInt m_g_y; |
127 | | BigInt m_order; |
128 | | BigInt m_cofactor; |
129 | | Modular_Reducer m_mod_order; |
130 | | PointGFp_Base_Point_Precompute m_base_mult; |
131 | | OID m_oid; |
132 | | size_t m_p_bits; |
133 | | size_t m_order_bits; |
134 | | bool m_a_is_minus_3; |
135 | | bool m_a_is_zero; |
136 | | }; |
137 | | |
138 | | class EC_Group_Data_Map final |
139 | | { |
140 | | public: |
141 | 9 | EC_Group_Data_Map() {} |
142 | | |
143 | | size_t clear() |
144 | 2.95k | { |
145 | 2.95k | lock_guard_type<mutex_type> lock(m_mutex); |
146 | 2.95k | size_t count = m_registered_curves.size(); |
147 | 2.95k | m_registered_curves.clear(); |
148 | 2.95k | return count; |
149 | 2.95k | } |
150 | | |
151 | | std::shared_ptr<EC_Group_Data> lookup(const OID& oid) |
152 | 19.1k | { |
153 | 19.1k | lock_guard_type<mutex_type> lock(m_mutex); |
154 | 19.1k | |
155 | 19.1k | for(auto i : m_registered_curves) |
156 | 50.1k | { |
157 | 50.1k | if(i->oid() == oid) |
158 | 18.0k | return i; |
159 | 50.1k | } |
160 | 19.1k | |
161 | 19.1k | // Not found, check hardcoded data |
162 | 19.1k | std::shared_ptr<EC_Group_Data> data = EC_Group::EC_group_info(oid); |
163 | 1.13k | |
164 | 1.13k | if(data) |
165 | 1.03k | { |
166 | 1.03k | m_registered_curves.push_back(data); |
167 | 1.03k | return data; |
168 | 1.03k | } |
169 | 100 | |
170 | 100 | // Nope, unknown curve |
171 | 100 | return std::shared_ptr<EC_Group_Data>(); |
172 | 100 | } |
173 | | |
174 | | std::shared_ptr<EC_Group_Data> lookup_or_create(const BigInt& p, |
175 | | const BigInt& a, |
176 | | const BigInt& b, |
177 | | const BigInt& g_x, |
178 | | const BigInt& g_y, |
179 | | const BigInt& order, |
180 | | const BigInt& cofactor, |
181 | | const OID& oid) |
182 | 178 | { |
183 | 178 | lock_guard_type<mutex_type> lock(m_mutex); |
184 | 178 | |
185 | 178 | for(auto i : m_registered_curves) |
186 | 0 | { |
187 | 0 | if(!oid.empty()) |
188 | 0 | { |
189 | 0 | if(i->oid() == oid) |
190 | 0 | { |
191 | 0 | if(!i->match(p, a, b, g_x, g_y, order, cofactor)) |
192 | 0 | throw Invalid_Argument("Attempting to register a curve using OID " + oid.to_string() + |
193 | 0 | " but another curve is already registered using that OID"); |
194 | 0 | return i; |
195 | 0 | } |
196 | 0 | else if(i->oid().has_value()) |
197 | 0 | continue; // distinct OIDs so not a match |
198 | 0 | } |
199 | 0 | |
200 | 0 | if(i->match(p, a, b, g_x, g_y, order, cofactor)) |
201 | 0 | { |
202 | 0 | /* |
203 | 0 | * If the same curve was previously created without an OID |
204 | 0 | * but has been registered again using an OID, save that OID. |
205 | 0 | */ |
206 | 0 | if(oid.empty() == false) |
207 | 0 | { |
208 | 0 | if(i->oid().empty() == true) |
209 | 0 | { |
210 | 0 | i->set_oid(oid); |
211 | 0 | } |
212 | 0 | else |
213 | 0 | { |
214 | 0 | throw Invalid_Argument("Cannot register ECC group with OID " + oid.to_string() + |
215 | 0 | " already registered using " + i->oid().to_string()); |
216 | 0 | } |
217 | 0 | } |
218 | 0 | return i; |
219 | 0 | } |
220 | 0 | } |
221 | 178 | |
222 | 178 | // Not found - if OID is set try looking up that way |
223 | 178 | |
224 | 178 | if(oid.has_value()) |
225 | 0 | { |
226 | 0 | // Not located in existing store - try hardcoded data set |
227 | 0 | std::shared_ptr<EC_Group_Data> data = EC_Group::EC_group_info(oid); |
228 | 0 |
|
229 | 0 | if(data) |
230 | 0 | { |
231 | 0 | m_registered_curves.push_back(data); |
232 | 0 | return data; |
233 | 0 | } |
234 | 178 | } |
235 | 178 | |
236 | 178 | // Not found or no OID, add data and return |
237 | 178 | std::shared_ptr<EC_Group_Data> d = |
238 | 178 | std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid); |
239 | 178 | |
240 | 178 | m_registered_curves.push_back(d); |
241 | 178 | return d; |
242 | 178 | } |
243 | | |
244 | | private: |
245 | | mutex_type m_mutex; |
246 | | std::vector<std::shared_ptr<EC_Group_Data>> m_registered_curves; |
247 | | }; |
248 | | |
249 | | //static |
250 | | EC_Group_Data_Map& EC_Group::ec_group_data() |
251 | 22.3k | { |
252 | 22.3k | /* |
253 | 22.3k | * This exists purely to ensure the allocator is constructed before g_ec_data, |
254 | 22.3k | * which ensures that its destructor runs after ~g_ec_data is complete. |
255 | 22.3k | */ |
256 | 22.3k | |
257 | 22.3k | static Allocator_Initializer g_init_allocator; |
258 | 22.3k | static EC_Group_Data_Map g_ec_data; |
259 | 22.3k | return g_ec_data; |
260 | 22.3k | } |
261 | | |
262 | | //static |
263 | | size_t EC_Group::clear_registered_curve_data() |
264 | 2.95k | { |
265 | 2.95k | return ec_group_data().clear(); |
266 | 2.95k | } |
267 | | |
268 | | //static |
269 | | std::shared_ptr<EC_Group_Data> |
270 | | EC_Group::load_EC_group_info(const char* p_str, |
271 | | const char* a_str, |
272 | | const char* b_str, |
273 | | const char* g_x_str, |
274 | | const char* g_y_str, |
275 | | const char* order_str, |
276 | | const OID& oid) |
277 | 1.03k | { |
278 | 1.03k | const BigInt p(p_str); |
279 | 1.03k | const BigInt a(a_str); |
280 | 1.03k | const BigInt b(b_str); |
281 | 1.03k | const BigInt g_x(g_x_str); |
282 | 1.03k | const BigInt g_y(g_y_str); |
283 | 1.03k | const BigInt order(order_str); |
284 | 1.03k | const BigInt cofactor(1); // implicit |
285 | 1.03k | |
286 | 1.03k | return std::make_shared<EC_Group_Data>(p, a, b, g_x, g_y, order, cofactor, oid); |
287 | 1.03k | } |
288 | | |
289 | | //static |
290 | | std::shared_ptr<EC_Group_Data> EC_Group::BER_decode_EC_group(const uint8_t bits[], size_t len) |
291 | 3.86k | { |
292 | 3.86k | BER_Decoder ber(bits, len); |
293 | 3.86k | BER_Object obj = ber.get_next_object(); |
294 | 3.86k | |
295 | 3.86k | if(obj.type() == NULL_TAG) |
296 | 8 | { |
297 | 8 | throw Decoding_Error("Cannot handle ImplicitCA ECC parameters"); |
298 | 8 | } |
299 | 3.85k | else if(obj.type() == OBJECT_ID) |
300 | 3.26k | { |
301 | 3.26k | OID dom_par_oid; |
302 | 3.26k | BER_Decoder(bits, len).decode(dom_par_oid); |
303 | 3.26k | return ec_group_data().lookup(dom_par_oid); |
304 | 3.26k | } |
305 | 592 | else if(obj.type() == SEQUENCE) |
306 | 440 | { |
307 | 440 | BigInt p, a, b, order, cofactor; |
308 | 440 | std::vector<uint8_t> base_pt; |
309 | 440 | std::vector<uint8_t> seed; |
310 | 440 | |
311 | 440 | BER_Decoder(bits, len) |
312 | 440 | .start_cons(SEQUENCE) |
313 | 440 | .decode_and_check<size_t>(1, "Unknown ECC param version code") |
314 | 440 | .start_cons(SEQUENCE) |
315 | 440 | .decode_and_check(OID("1.2.840.10045.1.1"), |
316 | 440 | "Only prime ECC fields supported") |
317 | 440 | .decode(p) |
318 | 440 | .end_cons() |
319 | 440 | .start_cons(SEQUENCE) |
320 | 440 | .decode_octet_string_bigint(a) |
321 | 440 | .decode_octet_string_bigint(b) |
322 | 440 | .decode_optional_string(seed, BIT_STRING, BIT_STRING) |
323 | 440 | .end_cons() |
324 | 440 | .decode(base_pt, OCTET_STRING) |
325 | 440 | .decode(order) |
326 | 440 | .decode(cofactor) |
327 | 440 | .end_cons() |
328 | 440 | .verify_end(); |
329 | 440 | |
330 | 440 | if(p.bits() < 64 || p.is_negative() || !is_bailie_psw_probable_prime(p)) |
331 | 18 | throw Decoding_Error("Invalid ECC p parameter"); |
332 | 422 | |
333 | 422 | if(a.is_negative() || a >= p) |
334 | 19 | throw Decoding_Error("Invalid ECC a parameter"); |
335 | 403 | |
336 | 403 | if(b <= 0 || b >= p) |
337 | 4 | throw Decoding_Error("Invalid ECC b parameter"); |
338 | 399 | |
339 | 399 | if(order <= 0 || !is_bailie_psw_probable_prime(order)) |
340 | 24 | throw Decoding_Error("Invalid ECC order parameter"); |
341 | 375 | |
342 | 375 | if(cofactor <= 0 || cofactor >= 16) |
343 | 14 | throw Decoding_Error("Invalid ECC cofactor parameter"); |
344 | 361 | |
345 | 361 | std::pair<BigInt, BigInt> base_xy = Botan::OS2ECP(base_pt.data(), base_pt.size(), p, a, b); |
346 | 361 | |
347 | 361 | return ec_group_data().lookup_or_create(p, a, b, base_xy.first, base_xy.second, order, cofactor, OID()); |
348 | 361 | } |
349 | 152 | else |
350 | 152 | { |
351 | 152 | throw Decoding_Error("Unexpected tag while decoding ECC domain params"); |
352 | 152 | } |
353 | 3.86k | } |
354 | | |
355 | | EC_Group::EC_Group() |
356 | 17.3k | { |
357 | 17.3k | } |
358 | | |
359 | | EC_Group::~EC_Group() |
360 | 48.4k | { |
361 | 48.4k | // shared_ptr possibly freed here |
362 | 48.4k | } |
363 | | |
364 | | EC_Group::EC_Group(const OID& domain_oid) |
365 | 113 | { |
366 | 113 | this->m_data = ec_group_data().lookup(domain_oid); |
367 | 113 | if(!this->m_data) |
368 | 0 | throw Invalid_Argument("Unknown EC_Group " + domain_oid.to_string()); |
369 | 113 | } |
370 | | |
371 | | EC_Group::EC_Group(const std::string& str) |
372 | 15.8k | { |
373 | 15.8k | if(str == "") |
374 | 0 | return; // no initialization / uninitialized |
375 | 15.8k | |
376 | 15.8k | try |
377 | 15.8k | { |
378 | 15.8k | const OID oid = OID::from_string(str); |
379 | 15.8k | if(oid.has_value()) |
380 | 15.8k | m_data = ec_group_data().lookup(oid); |
381 | 15.8k | } |
382 | 15.8k | catch(...) |
383 | 15.8k | { |
384 | 0 | } |
385 | 15.8k | |
386 | 15.8k | if(m_data == nullptr) |
387 | 0 | { |
388 | 0 | if(str.size() > 30 && str.substr(0, 29) == "-----BEGIN EC PARAMETERS-----") |
389 | 0 | { |
390 | 0 | // OK try it as PEM ... |
391 | 0 | secure_vector<uint8_t> ber = PEM_Code::decode_check_label(str, "EC PARAMETERS"); |
392 | 0 | this->m_data = BER_decode_EC_group(ber.data(), ber.size()); |
393 | 0 | } |
394 | 0 | } |
395 | 15.8k | |
396 | 15.8k | if(m_data == nullptr) |
397 | 0 | throw Invalid_Argument("Unknown ECC group '" + str + "'"); |
398 | 15.8k | } |
399 | | |
400 | | //static |
401 | | std::string EC_Group::PEM_for_named_group(const std::string& name) |
402 | 0 | { |
403 | 0 | try |
404 | 0 | { |
405 | 0 | EC_Group group(name); |
406 | 0 | return group.PEM_encode(); |
407 | 0 | } |
408 | 0 | catch(...) |
409 | 0 | { |
410 | 0 | return ""; |
411 | 0 | } |
412 | 0 | } |
413 | | |
414 | | EC_Group::EC_Group(const BigInt& p, |
415 | | const BigInt& a, |
416 | | const BigInt& b, |
417 | | const BigInt& base_x, |
418 | | const BigInt& base_y, |
419 | | const BigInt& order, |
420 | | const BigInt& cofactor, |
421 | | const OID& oid) |
422 | 0 | { |
423 | 0 | m_data = ec_group_data().lookup_or_create(p, a, b, base_x, base_y, order, cofactor, oid); |
424 | 0 | } |
425 | | |
426 | | EC_Group::EC_Group(const std::vector<uint8_t>& ber) |
427 | 3.86k | { |
428 | 3.86k | m_data = BER_decode_EC_group(ber.data(), ber.size()); |
429 | 3.86k | } |
430 | | |
431 | | const EC_Group_Data& EC_Group::data() const |
432 | 155k | { |
433 | 155k | if(m_data == nullptr) |
434 | 100 | throw Invalid_State("EC_Group uninitialized"); |
435 | 155k | return *m_data; |
436 | 155k | } |
437 | | |
438 | | const CurveGFp& EC_Group::get_curve() const |
439 | 0 | { |
440 | 0 | return data().curve(); |
441 | 0 | } |
442 | | |
443 | | bool EC_Group::a_is_minus_3() const |
444 | 0 | { |
445 | 0 | return data().a_is_minus_3(); |
446 | 0 | } |
447 | | |
448 | | bool EC_Group::a_is_zero() const |
449 | 0 | { |
450 | 0 | return data().a_is_zero(); |
451 | 0 | } |
452 | | |
453 | | size_t EC_Group::get_p_bits() const |
454 | 332 | { |
455 | 332 | return data().p_bits(); |
456 | 332 | } |
457 | | |
458 | | size_t EC_Group::get_p_bytes() const |
459 | 8.95k | { |
460 | 8.95k | return data().p_bytes(); |
461 | 8.95k | } |
462 | | |
463 | | size_t EC_Group::get_order_bits() const |
464 | 746 | { |
465 | 746 | return data().order_bits(); |
466 | 746 | } |
467 | | |
468 | | size_t EC_Group::get_order_bytes() const |
469 | 373 | { |
470 | 373 | return data().order_bytes(); |
471 | 373 | } |
472 | | |
473 | | const BigInt& EC_Group::get_p() const |
474 | 2.59k | { |
475 | 2.59k | return data().p(); |
476 | 2.59k | } |
477 | | |
478 | | const BigInt& EC_Group::get_a() const |
479 | 2.59k | { |
480 | 2.59k | return data().a(); |
481 | 2.59k | } |
482 | | |
483 | | const BigInt& EC_Group::get_b() const |
484 | 2.59k | { |
485 | 2.59k | return data().b(); |
486 | 2.59k | } |
487 | | |
488 | | const PointGFp& EC_Group::get_base_point() const |
489 | 1.41k | { |
490 | 1.41k | return data().base_point(); |
491 | 1.41k | } |
492 | | |
493 | | const BigInt& EC_Group::get_order() const |
494 | 37.2k | { |
495 | 37.2k | return data().order(); |
496 | 37.2k | } |
497 | | |
498 | | const BigInt& EC_Group::get_g_x() const |
499 | 0 | { |
500 | 0 | return data().g_x(); |
501 | 0 | } |
502 | | |
503 | | const BigInt& EC_Group::get_g_y() const |
504 | 0 | { |
505 | 0 | return data().g_y(); |
506 | 0 | } |
507 | | |
508 | | const BigInt& EC_Group::get_cofactor() const |
509 | 21.0k | { |
510 | 21.0k | return data().cofactor(); |
511 | 21.0k | } |
512 | | |
513 | | BigInt EC_Group::mod_order(const BigInt& k) const |
514 | 708 | { |
515 | 708 | return data().mod_order(k); |
516 | 708 | } |
517 | | |
518 | | BigInt EC_Group::square_mod_order(const BigInt& x) const |
519 | 0 | { |
520 | 0 | return data().square_mod_order(x); |
521 | 0 | } |
522 | | |
523 | | BigInt EC_Group::multiply_mod_order(const BigInt& x, const BigInt& y) const |
524 | 726 | { |
525 | 726 | return data().multiply_mod_order(x, y); |
526 | 726 | } |
527 | | |
528 | | BigInt EC_Group::multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const |
529 | 0 | { |
530 | 0 | return data().multiply_mod_order(x, y, z); |
531 | 0 | } |
532 | | |
533 | | BigInt EC_Group::inverse_mod_order(const BigInt& x) const |
534 | 10.9k | { |
535 | 10.9k | return data().inverse_mod_order(x); |
536 | 10.9k | } |
537 | | |
538 | | const OID& EC_Group::get_curve_oid() const |
539 | 18.7k | { |
540 | 18.7k | return data().oid(); |
541 | 18.7k | } |
542 | | |
543 | | size_t EC_Group::point_size(PointGFp::Compression_Type format) const |
544 | 0 | { |
545 | 0 | // Hybrid and standard format are (x,y), compressed is y, +1 format byte |
546 | 0 | if(format == PointGFp::COMPRESSED) |
547 | 0 | return (1 + get_p_bytes()); |
548 | 0 | else |
549 | 0 | return (1 + 2*get_p_bytes()); |
550 | 0 | } |
551 | | |
552 | | PointGFp EC_Group::OS2ECP(const uint8_t bits[], size_t len) const |
553 | 20.0k | { |
554 | 20.0k | return Botan::OS2ECP(bits, len, data().curve()); |
555 | 20.0k | } |
556 | | |
557 | | PointGFp EC_Group::point(const BigInt& x, const BigInt& y) const |
558 | 2.83k | { |
559 | 2.83k | // TODO: randomize the representation? |
560 | 2.83k | return PointGFp(data().curve(), x, y); |
561 | 2.83k | } |
562 | | |
563 | | PointGFp EC_Group::point_multiply(const BigInt& x, const PointGFp& pt, const BigInt& y) const |
564 | 0 | { |
565 | 0 | PointGFp_Multi_Point_Precompute xy_mul(get_base_point(), pt); |
566 | 0 | return xy_mul.multi_exp(x, y); |
567 | 0 | } |
568 | | |
569 | | PointGFp EC_Group::blinded_base_point_multiply(const BigInt& k, |
570 | | RandomNumberGenerator& rng, |
571 | | std::vector<BigInt>& ws) const |
572 | 23.7k | { |
573 | 23.7k | return data().blinded_base_point_multiply(k, rng, ws); |
574 | 23.7k | } |
575 | | |
576 | | BigInt EC_Group::blinded_base_point_multiply_x(const BigInt& k, |
577 | | RandomNumberGenerator& rng, |
578 | | std::vector<BigInt>& ws) const |
579 | 0 | { |
580 | 0 | const PointGFp pt = data().blinded_base_point_multiply(k, rng, ws); |
581 | 0 |
|
582 | 0 | if(pt.is_zero()) |
583 | 0 | return 0; |
584 | 0 | return pt.get_affine_x(); |
585 | 0 | } |
586 | | |
587 | | BigInt EC_Group::random_scalar(RandomNumberGenerator& rng) const |
588 | 15.9k | { |
589 | 15.9k | return BigInt::random_integer(rng, 1, get_order()); |
590 | 15.9k | } |
591 | | |
592 | | PointGFp EC_Group::blinded_var_point_multiply(const PointGFp& point, |
593 | | const BigInt& k, |
594 | | RandomNumberGenerator& rng, |
595 | | std::vector<BigInt>& ws) const |
596 | 19.4k | { |
597 | 19.4k | PointGFp_Var_Point_Precompute mul(point, rng, ws); |
598 | 19.4k | return mul.mul(k, rng, get_order(), ws); |
599 | 19.4k | } |
600 | | |
601 | | PointGFp EC_Group::zero_point() const |
602 | 0 | { |
603 | 0 | return PointGFp(data().curve()); |
604 | 0 | } |
605 | | |
606 | | std::vector<uint8_t> |
607 | | EC_Group::DER_encode(EC_Group_Encoding form) const |
608 | 0 | { |
609 | 0 | std::vector<uint8_t> output; |
610 | 0 |
|
611 | 0 | DER_Encoder der(output); |
612 | 0 |
|
613 | 0 | if(form == EC_DOMPAR_ENC_EXPLICIT) |
614 | 0 | { |
615 | 0 | const size_t ecpVers1 = 1; |
616 | 0 | const OID curve_type("1.2.840.10045.1.1"); // prime field |
617 | 0 |
|
618 | 0 | const size_t p_bytes = get_p_bytes(); |
619 | 0 |
|
620 | 0 | der.start_cons(SEQUENCE) |
621 | 0 | .encode(ecpVers1) |
622 | 0 | .start_cons(SEQUENCE) |
623 | 0 | .encode(curve_type) |
624 | 0 | .encode(get_p()) |
625 | 0 | .end_cons() |
626 | 0 | .start_cons(SEQUENCE) |
627 | 0 | .encode(BigInt::encode_1363(get_a(), p_bytes), |
628 | 0 | OCTET_STRING) |
629 | 0 | .encode(BigInt::encode_1363(get_b(), p_bytes), |
630 | 0 | OCTET_STRING) |
631 | 0 | .end_cons() |
632 | 0 | .encode(get_base_point().encode(PointGFp::UNCOMPRESSED), OCTET_STRING) |
633 | 0 | .encode(get_order()) |
634 | 0 | .encode(get_cofactor()) |
635 | 0 | .end_cons(); |
636 | 0 | } |
637 | 0 | else if(form == EC_DOMPAR_ENC_OID) |
638 | 0 | { |
639 | 0 | const OID oid = get_curve_oid(); |
640 | 0 | if(oid.empty()) |
641 | 0 | { |
642 | 0 | throw Encoding_Error("Cannot encode EC_Group as OID because OID not set"); |
643 | 0 | } |
644 | 0 | der.encode(oid); |
645 | 0 | } |
646 | 0 | else if(form == EC_DOMPAR_ENC_IMPLICITCA) |
647 | 0 | { |
648 | 0 | der.encode_null(); |
649 | 0 | } |
650 | 0 | else |
651 | 0 | { |
652 | 0 | throw Internal_Error("EC_Group::DER_encode: Unknown encoding"); |
653 | 0 | } |
654 | 0 | |
655 | 0 | return output; |
656 | 0 | } |
657 | | |
658 | | std::string EC_Group::PEM_encode() const |
659 | 0 | { |
660 | 0 | const std::vector<uint8_t> der = DER_encode(EC_DOMPAR_ENC_EXPLICIT); |
661 | 0 | return PEM_Code::encode(der, "EC PARAMETERS"); |
662 | 0 | } |
663 | | |
664 | | bool EC_Group::operator==(const EC_Group& other) const |
665 | 0 | { |
666 | 0 | if(m_data == other.m_data) |
667 | 0 | return true; // same shared rep |
668 | 0 | |
669 | 0 | /* |
670 | 0 | * No point comparing order/cofactor as they are uniquely determined |
671 | 0 | * by the curve equation (p,a,b) and the base point. |
672 | 0 | */ |
673 | 0 | return (get_p() == other.get_p() && |
674 | 0 | get_a() == other.get_a() && |
675 | 0 | get_b() == other.get_b() && |
676 | 0 | get_g_x() == other.get_g_x() && |
677 | 0 | get_g_y() == other.get_g_y()); |
678 | 0 | } |
679 | | |
680 | | bool EC_Group::verify_public_element(const PointGFp& point) const |
681 | 0 | { |
682 | 0 | //check that public point is not at infinity |
683 | 0 | if(point.is_zero()) |
684 | 0 | return false; |
685 | 0 | |
686 | 0 | //check that public point is on the curve |
687 | 0 | if(point.on_the_curve() == false) |
688 | 0 | return false; |
689 | 0 | |
690 | 0 | //check that public point has order q |
691 | 0 | if((point * get_order()).is_zero() == false) |
692 | 0 | return false; |
693 | 0 | |
694 | 0 | if(get_cofactor() > 1) |
695 | 0 | { |
696 | 0 | if((point * get_cofactor()).is_zero()) |
697 | 0 | return false; |
698 | 0 | } |
699 | 0 | |
700 | 0 | return true; |
701 | 0 | } |
702 | | |
703 | | bool EC_Group::verify_group(RandomNumberGenerator& rng, |
704 | | bool) const |
705 | 0 | { |
706 | 0 | const BigInt& p = get_p(); |
707 | 0 | const BigInt& a = get_a(); |
708 | 0 | const BigInt& b = get_b(); |
709 | 0 | const BigInt& order = get_order(); |
710 | 0 | const PointGFp& base_point = get_base_point(); |
711 | 0 |
|
712 | 0 | if(a < 0 || a >= p) |
713 | 0 | return false; |
714 | 0 | if(b <= 0 || b >= p) |
715 | 0 | return false; |
716 | 0 | if(order <= 0) |
717 | 0 | return false; |
718 | 0 | |
719 | 0 | //check if field modulus is prime |
720 | 0 | if(!is_prime(p, rng, 128)) |
721 | 0 | { |
722 | 0 | return false; |
723 | 0 | } |
724 | 0 | |
725 | 0 | //check if order is prime |
726 | 0 | if(!is_prime(order, rng, 128)) |
727 | 0 | { |
728 | 0 | return false; |
729 | 0 | } |
730 | 0 | |
731 | 0 | //compute the discriminant: 4*a^3 + 27*b^2 which must be nonzero |
732 | 0 | const Modular_Reducer mod_p(p); |
733 | 0 |
|
734 | 0 | const BigInt discriminant = mod_p.reduce( |
735 | 0 | mod_p.multiply(4, mod_p.cube(a)) + |
736 | 0 | mod_p.multiply(27, mod_p.square(b))); |
737 | 0 |
|
738 | 0 | if(discriminant == 0) |
739 | 0 | { |
740 | 0 | return false; |
741 | 0 | } |
742 | 0 | |
743 | 0 | //check for valid cofactor |
744 | 0 | if(get_cofactor() < 1) |
745 | 0 | { |
746 | 0 | return false; |
747 | 0 | } |
748 | 0 | |
749 | 0 | //check if the base point is on the curve |
750 | 0 | if(!base_point.on_the_curve()) |
751 | 0 | { |
752 | 0 | return false; |
753 | 0 | } |
754 | 0 | if((base_point * get_cofactor()).is_zero()) |
755 | 0 | { |
756 | 0 | return false; |
757 | 0 | } |
758 | 0 | //check if order of the base point is correct |
759 | 0 | if(!(base_point * order).is_zero()) |
760 | 0 | { |
761 | 0 | return false; |
762 | 0 | } |
763 | 0 | |
764 | 0 | return true; |
765 | 0 | } |
766 | | |
767 | | } |