• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 11844561993

14 Nov 2024 07:58PM UTC coverage: 91.178% (+0.1%) from 91.072%
11844561993

Pull #4435

github

web-flow
Merge 81dcb29da into e430f157a
Pull Request #4435: Test duration values ​​are now presented in seconds with six digits of precision. Tests without time measurements have been edited.

91856 of 100744 relevant lines covered (91.18%)

9311006.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.6
/src/tests/test_ec_group.cpp
1
/*
2
* (C) 2007 Falko Strenzke
3
*     2007 Manuel Hartl
4
*     2009,2015,2018,2021 Jack Lloyd
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#include "tests.h"
10

11
#if defined(BOTAN_HAS_ECC_GROUP)
12
   #include <botan/bigint.h>
13
   #include <botan/data_src.h>
14
   #include <botan/ec_group.h>
15
   #include <botan/ec_point.h>
16
   #include <botan/hex.h>
17
   #include <botan/numthry.h>
18
   #include <botan/pk_keys.h>
19
   #include <botan/reducer.h>
20
   #include <botan/x509_key.h>
21
#endif
22

23
namespace Botan_Tests {
24

25
namespace {
26

27
#if defined(BOTAN_HAS_ECC_GROUP)
28

29
Botan::BigInt test_integer(Botan::RandomNumberGenerator& rng, size_t bits, const BigInt& max) {
560✔
30
   /*
31
   Produces integers with long runs of ones and zeros, for testing for
32
   carry handling problems.
33
   */
34
   Botan::BigInt x = 0;
560✔
35

36
   auto flip_prob = [](size_t i) -> double {
154,040✔
37
      if(i % 64 == 0) {
153,480✔
38
         return .5;
39
      }
40
      if(i % 32 == 0) {
150,980✔
41
         return .4;
42
      }
43
      if(i % 8 == 0) {
148,560✔
44
         return .05;
14,360✔
45
      }
46
      return .01;
47
   };
48

49
   bool active = (rng.next_byte() > 128) ? true : false;
560✔
50
   for(size_t i = 0; i != bits; ++i) {
154,040✔
51
      x <<= 1;
153,480✔
52
      x += static_cast<int>(active);
153,480✔
53

54
      const double prob = flip_prob(i);
153,480✔
55
      const double sample = double(rng.next_byte() % 100) / 100.0;  // biased
153,480✔
56

57
      if(sample < prob) {
153,480✔
58
         active = !active;
5,122✔
59
      }
60
   }
61

62
   if(x == 0) {
560✔
63
      // EC_Scalar rejects zero as an input, if we hit this case instead
64
      // test with a completely randomized scalar
65
      return BigInt::random_integer(rng, 1, max);
×
66
   }
67

68
   if(max > 0) {
560✔
69
      while(x >= max) {
636✔
70
         const size_t b = x.bits() - 1;
76✔
71
         BOTAN_ASSERT(x.get_bit(b) == true, "Set");
152✔
72
         x.clear_bit(b);
76✔
73
      }
74
   }
75

76
   return x;
560✔
77
}
560✔
78

79
Botan::EC_Point create_random_point(Botan::RandomNumberGenerator& rng, const Botan::EC_Group& group) {
112✔
80
   const Botan::BigInt& p = group.get_p();
112✔
81
   const Botan::Modular_Reducer mod_p(p);
112✔
82

83
   for(;;) {
304✔
84
      const Botan::BigInt x = Botan::BigInt::random_integer(rng, 1, p);
208✔
85
      const Botan::BigInt x3 = mod_p.multiply(x, mod_p.square(x));
208✔
86
      const Botan::BigInt ax = mod_p.multiply(group.get_a(), x);
208✔
87
      const Botan::BigInt y = mod_p.reduce(x3 + ax + group.get_b());
416✔
88
      const Botan::BigInt sqrt_y = Botan::sqrt_modulo_prime(y, p);
208✔
89

90
      if(sqrt_y > 1) {
208✔
91
         BOTAN_ASSERT_EQUAL(mod_p.square(sqrt_y), y, "Square root is correct");
336✔
92
         return group.point(x, sqrt_y);
224✔
93
      }
94
   }
928✔
95
}
112✔
96

97
class ECC_Randomized_Tests final : public Test {
×
98
   public:
99
      std::vector<Test::Result> run() override;
100
};
101

102
std::vector<Test::Result> ECC_Randomized_Tests::run() {
1✔
103
   std::vector<Test::Result> results;
1✔
104
   for(const std::string& group_name : Botan::EC_Group::known_named_groups()) {
29✔
105
      Test::Result result("ECC randomized " + group_name);
28✔
106

107
      result.start_timer();
28✔
108

109
      auto group = Botan::EC_Group::from_name(group_name);
28✔
110

111
      const Botan::EC_Point pt = create_random_point(this->rng(), group);
28✔
112

113
      std::vector<Botan::BigInt> blind_ws;
28✔
114

115
      try {
28✔
116
         const size_t trials = (Test::run_long_tests() ? 10 : 3);
28✔
117
         for(size_t i = 0; i < trials; ++i) {
308✔
118
            const Botan::BigInt a = test_integer(rng(), group.get_order_bits(), group.get_order());
280✔
119
            const Botan::BigInt b = test_integer(rng(), group.get_order_bits(), group.get_order());
280✔
120
            const Botan::BigInt c = group.mod_order(a + b);
280✔
121

122
            const Botan::EC_Point P = pt * a;
280✔
123
            const Botan::EC_Point Q = pt * b;
280✔
124
            const Botan::EC_Point R = pt * c;
280✔
125

126
            Botan::EC_Point P1 = group.blinded_var_point_multiply(pt, a, this->rng(), blind_ws);
280✔
127
            Botan::EC_Point Q1 = group.blinded_var_point_multiply(pt, b, this->rng(), blind_ws);
280✔
128
            Botan::EC_Point R1 = group.blinded_var_point_multiply(pt, c, this->rng(), blind_ws);
280✔
129

130
            Botan::EC_Point A1 = P + Q;
280✔
131
            Botan::EC_Point A2 = Q + P;
280✔
132

133
            result.test_eq("p + q", A1, R);
280✔
134
            result.test_eq("q + p", A2, R);
280✔
135

136
            A1.force_affine();
280✔
137
            A2.force_affine();
280✔
138
            result.test_eq("p + q", A1, R);
280✔
139
            result.test_eq("q + p", A2, R);
280✔
140

141
            result.test_eq("p on the curve", P.on_the_curve(), true);
280✔
142
            result.test_eq("q on the curve", Q.on_the_curve(), true);
280✔
143
            result.test_eq("r on the curve", R.on_the_curve(), true);
280✔
144

145
            result.test_eq("P1", P1, P);
280✔
146
            result.test_eq("Q1", Q1, Q);
280✔
147
            result.test_eq("R1", R1, R);
280✔
148

149
            P1.force_affine();
280✔
150
            Q1.force_affine();
280✔
151
            R1.force_affine();
280✔
152
            result.test_eq("P1", P1, P);
280✔
153
            result.test_eq("Q1", Q1, Q);
280✔
154
            result.test_eq("R1", R1, R);
280✔
155
         }
1,120✔
156
      } catch(std::exception& e) {
×
157
         result.test_failure(group_name, e.what());
×
158
      }
×
159
      result.end_timer();
28✔
160
      results.push_back(result);
28✔
161
   }
28✔
162

163
   return results;
1✔
164
}
×
165

166
BOTAN_REGISTER_TEST("pubkey", "ecc_randomized", ECC_Randomized_Tests);
167

168
class EC_Group_Tests : public Test {
×
169
   public:
170
      std::vector<Test::Result> run() override {
1✔
171
         std::vector<Test::Result> results;
1✔
172

173
         for(const std::string& group_name : Botan::EC_Group::known_named_groups()) {
29✔
174
            Test::Result result("EC_Group " + group_name);
28✔
175

176
            result.start_timer();
28✔
177

178
            const auto group = Botan::EC_Group::from_name(group_name);
28✔
179

180
            result.confirm("EC_Group is known", group.get_curve_oid().has_value());
56✔
181
            result.confirm("EC_Group is considered valid", group.verify_group(this->rng(), true));
56✔
182
            result.confirm("EC_Group is not considered explict encoding", !group.used_explicit_encoding());
56✔
183

184
            result.test_eq("EC_Group has correct bit size", group.get_p().bits(), group.get_p_bits());
28✔
185
            result.test_eq("EC_Group has byte size", group.get_p().bytes(), group.get_p_bytes());
28✔
186

187
            result.test_eq("EC_Group has cofactor == 1", group.get_cofactor(), 1);
56✔
188

189
            const Botan::OID from_order = Botan::EC_Group::EC_group_identity_from_order(group.get_order());
28✔
190

191
            result.test_eq(
56✔
192
               "EC_group_identity_from_order works", from_order.to_string(), group.get_curve_oid().to_string());
56✔
193

194
            result.confirm("Same group is same", group == Botan::EC_Group::from_name(group_name));
56✔
195

196
            try {
28✔
197
               const Botan::EC_Group copy(group.get_curve_oid(),
28✔
198
                                          group.get_p(),
199
                                          group.get_a(),
200
                                          group.get_b(),
201
                                          group.get_g_x(),
202
                                          group.get_g_y(),
203
                                          group.get_order());
28✔
204

205
               result.confirm("Same group is same even with copy", group == copy);
40✔
206
            } catch(Botan::Invalid_Argument&) {}
28✔
207

208
            const auto group_der_oid = group.DER_encode();
28✔
209
            const Botan::EC_Group group_via_oid(group_der_oid);
28✔
210
            result.confirm("EC_Group via OID is not considered explict encoding",
56✔
211
                           !group_via_oid.used_explicit_encoding());
28✔
212

213
            const auto group_der_explicit = group.DER_encode(Botan::EC_Group_Encoding::Explicit);
28✔
214
            const Botan::EC_Group group_via_explicit(group_der_explicit);
28✔
215
            result.confirm("EC_Group via explicit DER is considered explict encoding",
56✔
216
                           group_via_explicit.used_explicit_encoding());
28✔
217

218
            const auto pt_mult_by_order = group.get_base_point() * group.get_order();
28✔
219
            result.confirm("Multiplying point by the order results in zero point", pt_mult_by_order.is_zero());
56✔
220

221
            if(group.a_is_minus_3()) {
28✔
222
               result.test_eq("Group A equals -3", group.get_a(), group.get_p() - 3);
51✔
223
            } else {
224
               result.test_ne("Group " + group_name + " A does not equal -3", group.get_a(), group.get_p() - 3);
44✔
225
            }
226

227
            if(group.a_is_zero()) {
28✔
228
               result.test_eq("Group A is zero", group.get_a(), BigInt(0));
8✔
229
            } else {
230
               result.test_ne("Group " + group_name + " A does not equal zero", group.get_a(), BigInt(0));
72✔
231
            }
232

233
            // get a valid point
234
            Botan::EC_Point p = group.get_base_point() * this->rng().next_nonzero_byte();
28✔
235

236
            // get a copy
237
            Botan::EC_Point q = p;
28✔
238

239
            p.randomize_repr(this->rng());
28✔
240
            q.randomize_repr(this->rng());
28✔
241

242
            result.test_eq("affine x after copy", p.get_affine_x(), q.get_affine_x());
84✔
243
            result.test_eq("affine y after copy", p.get_affine_y(), q.get_affine_y());
84✔
244

245
            q.force_affine();
28✔
246

247
            result.test_eq("affine x after copy", p.get_affine_x(), q.get_affine_x());
84✔
248
            result.test_eq("affine y after copy", p.get_affine_y(), q.get_affine_y());
84✔
249

250
            test_ser_der(result, group);
28✔
251
            test_basic_math(result, group);
28✔
252
            test_point_swap(result, group);
28✔
253
            test_zeropoint(result, group);
28✔
254

255
            result.end_timer();
28✔
256

257
            results.push_back(result);
28✔
258
         }
84✔
259

260
         return results;
1✔
261
      }
×
262

263
   private:
264
      void test_ser_der(Test::Result& result, const Botan::EC_Group& group) {
28✔
265
         // generate point
266
         const Botan::EC_Point pt = create_random_point(this->rng(), group);
28✔
267
         const Botan::EC_Point zero = group.zero_point();
28✔
268

269
         for(auto scheme : {Botan::EC_Point_Format::Uncompressed,
196✔
270
                            Botan::EC_Point_Format::Compressed,
271
                            Botan::EC_Point_Format::Hybrid}) {
112✔
272
            result.test_eq("encoded/decode rt works", group.OS2ECP(pt.encode(scheme)), pt);
168✔
273
            result.test_eq("encoded/decode rt works", group.OS2ECP(zero.encode(scheme)), zero);
252✔
274
         }
275
      }
28✔
276

277
      static void test_basic_math(Test::Result& result, const Botan::EC_Group& group) {
28✔
278
         const Botan::EC_Point& G = group.get_base_point();
28✔
279

280
         Botan::EC_Point p1 = G * 2;
56✔
281
         p1 += G;
28✔
282

283
         result.test_eq("point addition", p1, G * 3);
84✔
284

285
         p1 -= G * 2;
56✔
286

287
         result.test_eq("point subtraction", p1, G);
28✔
288

289
         // The scalar multiplication algorithm relies on this being true:
290
         try {
28✔
291
            Botan::EC_Point zero_coords = group.point(0, 0);
56✔
292
            result.confirm("point (0,0) is not on the curve", !zero_coords.on_the_curve());
×
293
         } catch(Botan::Exception&) {
28✔
294
            result.test_success("point (0,0) is rejected");
28✔
295
         }
28✔
296
      }
28✔
297

298
      void test_point_swap(Test::Result& result, const Botan::EC_Group& group) {
28✔
299
         Botan::EC_Point a(create_random_point(this->rng(), group));
28✔
300
         Botan::EC_Point b(create_random_point(this->rng(), group));
28✔
301
         b *= Botan::BigInt(this->rng(), 20);
28✔
302

303
         Botan::EC_Point c(a);
28✔
304
         Botan::EC_Point d(b);
28✔
305

306
         d.swap(c);
28✔
307
         result.test_eq("swap correct", a, d);
28✔
308
         result.test_eq("swap correct", b, c);
28✔
309
      }
28✔
310

311
      static void test_zeropoint(Test::Result& result, const Botan::EC_Group& group) {
28✔
312
         Botan::EC_Point zero = group.zero_point();
28✔
313

314
         result.test_throws("Zero point throws", "Cannot convert zero point to affine", [&]() { zero.get_affine_x(); });
84✔
315
         result.test_throws("Zero point throws", "Cannot convert zero point to affine", [&]() { zero.get_affine_y(); });
84✔
316

317
         const Botan::EC_Point p1 = group.get_base_point() * 2;
28✔
318

319
         result.confirm("point is on the curve", p1.on_the_curve());
56✔
320
         result.confirm("point is not zero", !p1.is_zero());
56✔
321

322
         Botan::EC_Point p2 = p1;
28✔
323
         p2 -= p1;
28✔
324

325
         result.confirm("p - q with q = p results in zero", p2.is_zero());
56✔
326

327
         const Botan::EC_Point minus_p1 = -p1;
28✔
328
         result.confirm("point is on the curve", minus_p1.on_the_curve());
56✔
329
         const Botan::EC_Point shouldBeZero = p1 + minus_p1;
28✔
330
         result.confirm("point is on the curve", shouldBeZero.on_the_curve());
56✔
331
         result.confirm("point is zero", shouldBeZero.is_zero());
56✔
332

333
         result.test_eq("minus point x", minus_p1.get_affine_x(), p1.get_affine_x());
84✔
334
         result.test_eq("minus point y", minus_p1.get_affine_y(), group.get_p() - p1.get_affine_y());
112✔
335

336
         result.confirm("zero point is zero", zero.is_zero());
56✔
337
         result.confirm("zero point is on the curve", zero.on_the_curve());
56✔
338
         result.test_eq("addition of zero does nothing", p1, p1 + zero);
56✔
339
         result.test_eq("addition of zero does nothing", p1, zero + p1);
56✔
340
         result.test_eq("addition of zero does nothing", p1, p1 - zero);
56✔
341
         result.confirm("zero times anything is the zero point", (zero * 39193).is_zero());
84✔
342

343
         for(auto scheme : {Botan::EC_Point_Format::Uncompressed,
196✔
344
                            Botan::EC_Point_Format::Compressed,
345
                            Botan::EC_Point_Format::Hybrid}) {
112✔
346
            const std::vector<uint8_t> v = zero.encode(scheme);
84✔
347
            result.test_eq("encoded/decode rt works", group.OS2ECP(v), zero);
168✔
348
         }
84✔
349
      }
28✔
350
};
351

352
BOTAN_REGISTER_TEST("pubkey", "ec_group", EC_Group_Tests);
353

354
Test::Result test_decoding_with_seed() {
1✔
355
   Test::Result result("ECC Unit");
1✔
356
   result.start_timer();
1✔
357

358
   const auto secp384r1_with_seed = Botan::EC_Group::from_PEM(Test::read_data_file("x509/ecc/secp384r1_seed.pem"));
2✔
359

360
   result.confirm("decoding worked", secp384r1_with_seed.initialized());
2✔
361

362
   const auto secp384r1 = Botan::EC_Group::from_name("secp384r1");
1✔
363

364
   result.test_eq("P-384 prime", secp384r1_with_seed.get_p(), secp384r1.get_p());
1✔
365

366
   result.end_timer();
1✔
367
   return result;
1✔
368
}
1✔
369

370
Test::Result test_mixed_points() {
1✔
371
   Test::Result result("ECC Unit");
1✔
372
   result.start_timer();
1✔
373

374
   const auto secp256r1 = Botan::EC_Group::from_name("secp256r1");
1✔
375
   const auto secp384r1 = Botan::EC_Group::from_name("secp384r1");
1✔
376

377
   const Botan::EC_Point& G256 = secp256r1.get_base_point();
1✔
378
   const Botan::EC_Point& G384 = secp384r1.get_base_point();
1✔
379

380
   result.test_throws("Mixing points from different groups", [&] { Botan::EC_Point p = G256 + G384; });
3✔
381
   
382
   result.end_timer();
1✔
383
   return result;
1✔
384
}
1✔
385

386
Test::Result test_basic_operations() {
1✔
387
   Test::Result result("ECC Unit");
1✔
388
   result.start_timer();
1✔
389

390
   // precalculation
391
   const auto secp160r1 = Botan::EC_Group::from_name("secp160r1");
1✔
392
   const Botan::EC_Point& p_G = secp160r1.get_base_point();
1✔
393

394
   const Botan::EC_Point& p0 = p_G;
1✔
395
   const Botan::EC_Point p1 = p_G * 2;
2✔
396

397
   result.test_eq("p1 affine x", p1.get_affine_x(), Botan::BigInt("16984103820118642236896513183038186009872590470"));
3✔
398
   result.test_eq("p1 affine y", p1.get_affine_y(), Botan::BigInt("1373093393927139016463695321221277758035357890939"));
3✔
399

400
   const Botan::EC_Point simplePlus = p1 + p0;
1✔
401
   const Botan::EC_Point exp_simplePlus =
1✔
402
      secp160r1.point(Botan::BigInt("704859595002530890444080436569091156047721708633"),
2✔
403
                      Botan::BigInt("1147993098458695153857594941635310323215433166682"));
2✔
404

405
   result.test_eq("point addition", simplePlus, exp_simplePlus);
1✔
406

407
   const Botan::EC_Point simpleMinus = p1 - p0;
1✔
408
   result.test_eq("point subtraction", simpleMinus, p_G);
1✔
409

410
   const Botan::EC_Point simpleMult = p1 * 123456789;
2✔
411

412
   result.test_eq("point mult affine x",
3✔
413
                  simpleMult.get_affine_x(),
2✔
414
                  Botan::BigInt("43638877777452195295055270548491599621118743290"));
1✔
415
   result.test_eq("point mult affine y",
3✔
416
                  simpleMult.get_affine_y(),
2✔
417
                  Botan::BigInt("56841378500012376527163928510402662349220202981"));
1✔
418

419
   result.end_timer();
1✔
420
   return result;
1✔
421
}
1✔
422

423
Test::Result test_enc_dec_compressed_160() {
1✔
424
   Test::Result result("ECC Unit");
1✔
425
   result.start_timer();
1✔
426

427
   // Test for compressed conversion (02/03) 160bit
428
   const auto secp160r1 = Botan::EC_Group::from_name("secp160r1");
1✔
429
   const std::vector<uint8_t> G_comp = Botan::hex_decode("024A96B5688EF573284664698968C38BB913CBFC82");
1✔
430
   const Botan::EC_Point p = secp160r1.OS2ECP(G_comp);
1✔
431
   const std::vector<uint8_t> sv_result = p.encode(Botan::EC_Point_Format::Compressed);
1✔
432

433
   result.test_eq("result", sv_result, G_comp);
1✔
434
   
435
   result.end_timer();
1✔
436
   return result;
2✔
437
}
2✔
438

439
Test::Result test_enc_dec_compressed_256() {
1✔
440
   Test::Result result("ECC Unit");
1✔
441
   result.start_timer();
1✔
442

443
   const auto group = Botan::EC_Group::from_name("secp256r1");
1✔
444

445
   const std::string G_secp_comp = "036B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296";
1✔
446
   const std::vector<uint8_t> sv_G_secp_comp = Botan::hex_decode(G_secp_comp);
1✔
447

448
   Botan::EC_Point p_G = group.OS2ECP(sv_G_secp_comp);
1✔
449
   std::vector<uint8_t> sv_result = p_G.encode(Botan::EC_Point_Format::Compressed);
1✔
450

451
   result.test_eq("compressed_256", sv_result, sv_G_secp_comp);
1✔
452

453
   result.end_timer();
1✔
454
   return result;
2✔
455
}
2✔
456

457
Test::Result test_enc_dec_uncompressed_112() {
1✔
458
   Test::Result result("ECC Unit");
1✔
459
   result.start_timer();
1✔
460

461
   // Test for uncompressed conversion (04) 112bit
462

463
   // Curve is secp112r2
464

465
   const Botan::BigInt p("0xdb7c2abf62e35e668076bead208b");
1✔
466
   const Botan::BigInt a("0x6127C24C05F38A0AAAF65C0EF02C");
1✔
467
   const Botan::BigInt b("0x51DEF1815DB5ED74FCC34C85D709");
1✔
468

469
   const Botan::BigInt g_x("0x4BA30AB5E892B4E1649DD0928643");
1✔
470
   const Botan::BigInt g_y("0xADCD46F5882E3747DEF36E956E97");
1✔
471

472
   const Botan::BigInt order("0x36DF0AAFD8B8D7597CA10520D04B");
1✔
473
   const Botan::BigInt cofactor("4");  // !
1✔
474

475
   // This uses the deprecated constructor due to making use of cofactor > 1
476
   const Botan::EC_Group group(p, a, b, g_x, g_y, order, cofactor);
1✔
477

478
   const std::string G_secp_uncomp = "044BA30AB5E892B4E1649DD0928643ADCD46F5882E3747DEF36E956E97";
1✔
479
   const std::vector<uint8_t> sv_G_secp_uncomp = Botan::hex_decode(G_secp_uncomp);
1✔
480

481
   Botan::EC_Point p_G = group.OS2ECP(sv_G_secp_uncomp);
1✔
482
   std::vector<uint8_t> sv_result = p_G.encode(Botan::EC_Point_Format::Uncompressed);
1✔
483

484
   result.test_eq("uncompressed_112", sv_result, sv_G_secp_uncomp);
1✔
485

486
   result.end_timer();
1✔
487
   return result;
1✔
488
}
9✔
489

490
Test::Result test_enc_dec_uncompressed_521() {
1✔
491
   Test::Result result("ECC Unit");
1✔
492
   result.start_timer();
1✔
493

494
   // Test for uncompressed conversion(04) with big values(521 bit)
495

496
   const std::string G_secp_uncomp =
1✔
497
      "0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2ffA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650";
1✔
498

499
   const std::vector<uint8_t> sv_G_secp_uncomp = Botan::hex_decode(G_secp_uncomp);
1✔
500

501
   const auto group = Botan::EC_Group::from_name("secp521r1");
1✔
502

503
   Botan::EC_Point p_G = group.OS2ECP(sv_G_secp_uncomp);
1✔
504

505
   std::vector<uint8_t> sv_result = p_G.encode(Botan::EC_Point_Format::Uncompressed);
1✔
506

507
   result.test_eq("expected", sv_result, sv_G_secp_uncomp);
1✔
508

509
   result.end_timer();
1✔
510
   return result;
1✔
511
}
2✔
512

513
Test::Result test_ecc_registration() {
1✔
514
   Test::Result result("ECC registration");
1✔
515
   result.start_timer();
1✔
516

517
   // secp128r1
518
   const Botan::BigInt p("0xfffffffdffffffffffffffffffffffff");
1✔
519
   const Botan::BigInt a("0xfffffffdfffffffffffffffffffffffc");
1✔
520
   const Botan::BigInt b("0xe87579c11079f43dd824993c2cee5ed3");
1✔
521

522
   const Botan::BigInt g_x("0x161ff7528b899b2d0c28607ca52c5b86");
1✔
523
   const Botan::BigInt g_y("0xcf5ac8395bafeb13c02da292dded7a83");
1✔
524
   const Botan::BigInt order("0xfffffffe0000000075a30d1b9038a115");
1✔
525

526
   const Botan::OID oid("1.3.132.0.28");
1✔
527

528
   // Creating this object implicitly registers the curve for future use ...
529
   Botan::EC_Group reg_group(oid, p, a, b, g_x, g_y, order);
1✔
530

531
   auto group = Botan::EC_Group::from_OID(oid);
1✔
532

533
   result.test_eq("Group registration worked", group.get_p(), p);
1✔
534

535
   result.end_timer();
1✔
536
   return result;
2✔
537
}
7✔
538

539
Test::Result test_ec_group_from_params() {
1✔
540
   Test::Result result("EC_Group from params");
1✔
541
   result.start_timer();
1✔
542

543
   Botan::EC_Group::clear_registered_curve_data();
1✔
544

545
   // secp256r1
546
   const Botan::BigInt p("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF");
1✔
547
   const Botan::BigInt a("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC");
1✔
548
   const Botan::BigInt b("0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B");
1✔
549

550
   const Botan::BigInt g_x("0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296");
1✔
551
   const Botan::BigInt g_y("0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5");
1✔
552
   const Botan::BigInt order("0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
1✔
553

554
   const Botan::OID oid("1.2.840.10045.3.1.7");
1✔
555

556
   // This uses the deprecated constructor to verify we dedup even without an OID
557
   // This whole test can be removed once explicit curve support is removed
558
   Botan::EC_Group reg_group(p, a, b, g_x, g_y, order, 1);
2✔
559
   result.confirm("Group has correct OID", reg_group.get_curve_oid() == oid);
2✔
560
   
561
   result.end_timer();
1✔
562
   return result;
2✔
563
}
7✔
564

565
Test::Result test_ec_group_bad_registration() {
1✔
566
   Test::Result result("EC_Group registering non-match");
1✔
567
   result.start_timer();
1✔
568

569
   Botan::EC_Group::clear_registered_curve_data();
1✔
570

571
   // secp256r1 params except with a bad B param
572
   const Botan::BigInt p("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF");
1✔
573
   const Botan::BigInt a("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC");
1✔
574
   const Botan::BigInt b("0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604C");
1✔
575

576
   const Botan::BigInt g_x("0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296");
1✔
577
   const Botan::BigInt g_y("0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5");
1✔
578
   const Botan::BigInt order("0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
1✔
579

580
   const Botan::OID oid("1.2.840.10045.3.1.7");
1✔
581

582
   try {
1✔
583
      Botan::EC_Group reg_group(oid, p, a, b, g_x, g_y, order);
1✔
584
      result.test_failure("Should have failed");
×
585
   } catch(Botan::Invalid_Argument&) {
1✔
586
      result.test_success("Got expected exception");
1✔
587
   }
1✔
588

589
   result.end_timer();
1✔
590
   return result;
1✔
591
}
7✔
592

593
Test::Result test_ec_group_duplicate_orders() {
1✔
594
   Test::Result result("EC_Group with duplicate group order");
1✔
595
   result.start_timer();
1✔
596

597
   Botan::EC_Group::clear_registered_curve_data();
1✔
598

599
   // secp256r1
600
   const Botan::BigInt p("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF");
1✔
601
   const Botan::BigInt a("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC");
1✔
602
   const Botan::BigInt b("0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B");
1✔
603

604
   const Botan::BigInt g_x("0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296");
1✔
605
   const Botan::BigInt g_y("0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5");
1✔
606
   const Botan::BigInt order("0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
1✔
607

608
   const Botan::OID oid("1.3.6.1.4.1.25258.100.0");  // some other random OID
1✔
609

610
   Botan::EC_Group reg_group(oid, p, a, b, g_x, g_y, order);
1✔
611
   result.test_success("Registration success");
1✔
612
   result.confirm("Group has correct OID", reg_group.get_curve_oid() == oid);
2✔
613

614
   // We can now get it by OID:
615
   const auto hc_group = Botan::EC_Group::from_OID(oid);
1✔
616
   result.confirm("Group has correct OID", hc_group.get_curve_oid() == oid);
2✔
617

618
   // Existing secp256r1 unmodified:
619
   const Botan::OID secp160r1("1.2.840.10045.3.1.7");
1✔
620
   const auto other_group = Botan::EC_Group::from_OID(secp160r1);
1✔
621
   result.confirm("Group has correct OID", other_group.get_curve_oid() == secp160r1);
2✔
622

623
   result.end_timer();
1✔
624
   return result;
2✔
625
}
7✔
626

627
class ECC_Unit_Tests final : public Test {
×
628
   public:
629
      std::vector<Test::Result> run() override {
1✔
630
         std::vector<Test::Result> results;
1✔
631

632
         results.push_back(test_decoding_with_seed());
2✔
633
         results.push_back(test_mixed_points());
2✔
634
         results.push_back(test_basic_operations());
2✔
635
         results.push_back(test_enc_dec_compressed_160());
2✔
636
         results.push_back(test_enc_dec_compressed_256());
2✔
637
         results.push_back(test_enc_dec_uncompressed_112());
2✔
638
         results.push_back(test_enc_dec_uncompressed_521());
2✔
639
         results.push_back(test_ecc_registration());
2✔
640
         results.push_back(test_ec_group_from_params());
2✔
641
         results.push_back(test_ec_group_bad_registration());
2✔
642
         results.push_back(test_ec_group_duplicate_orders());
2✔
643

644
         return results;
1✔
645
      }
×
646
};
647

648
BOTAN_REGISTER_SERIALIZED_TEST("pubkey", "ecc_unit", ECC_Unit_Tests);
649

650
   #if defined(BOTAN_HAS_ECDSA)
651

652
class ECC_Invalid_Key_Tests final : public Text_Based_Test {
×
653
   public:
654
      ECC_Invalid_Key_Tests() : Text_Based_Test("pubkey/ecc_invalid.vec", "SubjectPublicKey") {}
2✔
655

656
      bool clear_between_callbacks() const override { return false; }
5✔
657

658
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
5✔
659
         Test::Result result("ECC invalid keys");
5✔
660

661
         const std::string encoded = vars.get_req_str("SubjectPublicKey");
5✔
662
         Botan::DataSource_Memory key_data(Botan::hex_decode(encoded));
10✔
663

664
         try {
5✔
665
            auto key = Botan::X509::load_key(key_data);
5✔
666
            result.test_eq("public key fails check", key->check_key(this->rng(), false), false);
×
667
         } catch(Botan::Decoding_Error&) {
5✔
668
            result.test_success("Decoding invalid ECC key results in decoding error exception");
5✔
669
         }
5✔
670

671
         return result;
5✔
672
      }
5✔
673
};
674

675
BOTAN_REGISTER_TEST("pubkey", "ecc_invalid", ECC_Invalid_Key_Tests);
676

677
   #endif
678

679
#endif
680

681
}  // namespace
682

683
}  // namespace Botan_Tests
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc