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

randombit / botan / 30143835648

25 Jul 2026 02:00AM UTC coverage: 89.429% (+0.01%) from 89.419%
30143835648

push

github

web-flow
Merge pull request #5758 from randombit/jack/hash2curve-query

Add EC_Group::hash_to_curve_supported and enforce RFC 9380 hash requirements

114789 of 128357 relevant lines covered (89.43%)

10704638.98 hits per line

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

99.4
/src/cli/perf_ec.cpp
1
/*
2
* (C) 2024 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include "perf.h"
8

9
#if defined(BOTAN_HAS_ECC_GROUP)
10
   #include <botan/assert.h>
11
   #include <botan/ec_group.h>
12
   #include <botan/rng.h>
13
#endif
14

15
namespace Botan_CLI {
16

17
namespace {
18

19
#if defined(BOTAN_HAS_ECC_GROUP)
20

21
class PerfTest_EllipticCurve_Mul final : public PerfTest {
1✔
22
   public:
23
      void go(const PerfConfig& config) override {
1✔
24
         const auto run = config.runtime();
1✔
25
         auto& rng = config.rng();
1✔
26

27
         for(const auto& group_name : config.ecc_groups()) {
7✔
28
            const auto group = Botan::EC_Group::from_name(group_name);
6✔
29

30
            auto bp_timer = config.make_timer(group_name + " blinded base point mul");
12✔
31
            auto bp_nb_timer = config.make_timer(group_name + " unblinded base point mul");
12✔
32

33
            auto vp_timer = config.make_timer(group_name + " blinded variable point mul");
12✔
34
            auto vp_nb_timer = config.make_timer(group_name + " unblinded variable point mul");
12✔
35

36
            auto g = Botan::EC_AffinePoint::generator(group);
6✔
37

38
            Botan::Null_RNG null_rng;
6✔
39

40
            while(bp_timer->under(run) && vp_timer->under(run)) {
17✔
41
               const auto k = Botan::EC_Scalar::random(group, rng);
11✔
42

43
               const auto r1 = bp_timer->run([&]() { return Botan::EC_AffinePoint::g_mul(k, rng); });
22✔
44
               const auto r2 = vp_timer->run([&]() { return g.mul(k, rng); });
22✔
45
               const auto r3 = bp_nb_timer->run([&]() { return Botan::EC_AffinePoint::g_mul(k, null_rng); });
22✔
46
               const auto r4 = vp_nb_timer->run([&]() { return g.mul(k, null_rng); });
22✔
47

48
               BOTAN_ASSERT_NOMSG(r1 == r2);
11✔
49
               BOTAN_ASSERT_NOMSG(r1 == r3);
11✔
50
               BOTAN_ASSERT_NOMSG(r1 == r4);
11✔
51
            }
11✔
52

53
            config.record_result(*bp_timer);
6✔
54
            config.record_result(*bp_nb_timer);
6✔
55
            config.record_result(*vp_timer);
6✔
56
            config.record_result(*vp_nb_timer);
6✔
57
         }
24✔
58
      }
1✔
59
};
60

61
BOTAN_REGISTER_PERF_TEST("ecc_mul", PerfTest_EllipticCurve_Mul);
1✔
62

63
class PerfTest_EllipticCurve_Mul2 final : public PerfTest {
1✔
64
   public:
65
      void go(const PerfConfig& config) override {
1✔
66
         const auto run = config.runtime();
1✔
67
         auto& rng = config.rng();
1✔
68

69
         for(const auto& group_name : config.ecc_groups()) {
7✔
70
            const auto group = Botan::EC_Group::from_name(group_name);
6✔
71

72
            auto mul2_setup_timer = config.make_timer(group_name + " mul2_vartime setup");
12✔
73
            auto mul2_vt_timer = config.make_timer(group_name + " mul2_vartime");
12✔
74
            auto mul2_ct_timer = config.make_timer(group_name + " blinded mul2");
12✔
75
            auto mul2_ct_nb_timer = config.make_timer(group_name + " unblinded mul2");
12✔
76

77
            Botan::Null_RNG null_rng;
6✔
78

79
            auto g = Botan::EC_AffinePoint::generator(group);
6✔
80

81
            while(mul2_setup_timer->under(run) && mul2_ct_timer->under(run)) {
14✔
82
               const auto k = Botan::EC_Scalar::random(group, rng);
8✔
83
               const auto k2 = Botan::EC_Scalar::random(group, rng);
8✔
84

85
               const auto y = Botan::EC_AffinePoint::g_mul(Botan::EC_Scalar::random(group, rng), rng);
8✔
86

87
               auto mul2 = mul2_setup_timer->run([&]() { return Botan::EC_Group::Mul2Table(y); });
16✔
88

89
               auto pt = mul2_vt_timer->run([&]() { return mul2.mul2_vartime(k, k2); });
16✔
90

91
               auto pt2 = mul2_ct_timer->run([&]() { return Botan::EC_AffinePoint::mul_px_qy(g, k, y, k2, rng); });
16✔
92

93
               auto pt3 =
8✔
94
                  mul2_ct_nb_timer->run([&]() { return Botan::EC_AffinePoint::mul_px_qy(g, k, y, k2, null_rng); });
16✔
95

96
               BOTAN_ASSERT_NOMSG(pt == pt2);
8✔
97
               BOTAN_ASSERT_NOMSG(pt == pt3);
16✔
98
            }
24✔
99

100
            config.record_result(*mul2_setup_timer);
6✔
101
            config.record_result(*mul2_vt_timer);
6✔
102
            config.record_result(*mul2_ct_timer);
6✔
103
            config.record_result(*mul2_ct_nb_timer);
6✔
104
         }
24✔
105
      }
1✔
106
};
107

108
BOTAN_REGISTER_PERF_TEST("ecc_mul2", PerfTest_EllipticCurve_Mul2);
1✔
109

110
class PerfTest_EllipticCurve_H2C final : public PerfTest {
1✔
111
   public:
112
      void go(const PerfConfig& config) override {
1✔
113
         const auto run = config.runtime();
1✔
114
         auto& rng = config.rng();
1✔
115

116
         for(const auto& group_name : config.ecc_groups()) {
7✔
117
            const auto group = Botan::EC_Group::from_name(group_name);
6✔
118

119
            const std::string hash_fn = [&]() -> std::string {
18✔
120
               const size_t order_bits = group.get_order_bits();
6✔
121
               if(order_bits <= 256) {
6✔
122
                  return "SHA-256";
2✔
123
               } else if(order_bits <= 384) {
4✔
124
                  return "SHA-384";
2✔
125
               } else {
126
                  return "SHA-512";
2✔
127
               }
128
            }();
6✔
129

130
            if(!group.hash_to_curve_supported(hash_fn)) {
6✔
131
               continue;
×
132
            }
133

134
            auto h2c_nu_timer = config.make_timer(group_name + " hash to curve (NU)");
12✔
135
            auto h2c_ro_timer = config.make_timer(group_name + " hash to curve (RO)");
12✔
136

137
            std::vector<uint8_t> input(32);
6✔
138

139
            while(h2c_ro_timer->under(run)) {
32✔
140
               rng.randomize(input);
26✔
141
               h2c_nu_timer->run([&]() { Botan::EC_AffinePoint::hash_to_curve_nu(group, hash_fn, input, "domain"); });
52✔
142
               h2c_ro_timer->run([&]() { Botan::EC_AffinePoint::hash_to_curve_ro(group, hash_fn, input, "domain"); });
52✔
143
            }
144

145
            config.record_result(*h2c_nu_timer);
6✔
146
            config.record_result(*h2c_ro_timer);
12✔
147
         }
12✔
148
      }
1✔
149
};
150

151
BOTAN_REGISTER_PERF_TEST("ecc_h2c", PerfTest_EllipticCurve_H2C);
1✔
152

153
class PerfTest_EllipticCurve_Misc final : public PerfTest {
1✔
154
   public:
155
      void go(const PerfConfig& config) override {
1✔
156
         const auto run = config.runtime();
1✔
157
         auto& rng = config.rng();
1✔
158

159
         for(const auto& group_name : config.ecc_groups()) {
7✔
160
            auto init_timer = config.make_timer(group_name + " initialization");
12✔
161

162
            while(init_timer->under(run)) {
12✔
163
               Botan::EC_Group::clear_registered_curve_data();
6✔
164
               init_timer->run([&]() { Botan::EC_Group::from_name(group_name); });
12✔
165
            }
166

167
            config.record_result(*init_timer);
6✔
168

169
            const auto group = Botan::EC_Group::from_name(group_name);
6✔
170

171
            auto pt_add_timer = config.make_timer(group_name + " point addition");
12✔
172
            auto pt_neg_timer = config.make_timer(group_name + " point negation");
12✔
173
            auto der_uc_timer = config.make_timer(group_name + " point deserialize (uncompressed)");
12✔
174
            auto der_c_timer = config.make_timer(group_name + " point deserialize (compressed)");
12✔
175

176
            while(pt_add_timer->under(run) && der_c_timer->under(run)) {
84✔
177
               const auto r1 = Botan::EC_AffinePoint::g_mul(Botan::EC_Scalar::random(group, rng), rng);
78✔
178
               const auto r2 = Botan::EC_AffinePoint::g_mul(Botan::EC_Scalar::random(group, rng), rng);
78✔
179

180
               const auto r1_bytes = r1.serialize_uncompressed();
78✔
181
               const auto r2_bytes = r2.serialize_uncompressed();
78✔
182

183
               pt_add_timer->run([&]() { r1.add(r2); });
156✔
184
               pt_neg_timer->run([&]() { return r1.negate(); });
156✔
185

186
               der_uc_timer->run([&]() { Botan::EC_AffinePoint::deserialize(group, r1_bytes); });
156✔
187
               der_uc_timer->run([&]() { Botan::EC_AffinePoint::deserialize(group, r2_bytes); });
156✔
188

189
               const auto r1_cbytes = r1.serialize_compressed();
78✔
190
               const auto r2_cbytes = r2.serialize_compressed();
78✔
191
               der_c_timer->run([&]() { Botan::EC_AffinePoint::deserialize(group, r1_cbytes); });
156✔
192
               der_c_timer->run([&]() { Botan::EC_AffinePoint::deserialize(group, r2_cbytes); });
156✔
193
            }
312✔
194

195
            config.record_result(*pt_add_timer);
6✔
196
            config.record_result(*pt_neg_timer);
6✔
197
            config.record_result(*der_uc_timer);
6✔
198
            config.record_result(*der_c_timer);
12✔
199
         }
18✔
200
      }
1✔
201
};
202

203
BOTAN_REGISTER_PERF_TEST("ecc_misc", PerfTest_EllipticCurve_Misc);
1✔
204

205
class PerfTest_EllipticCurve_Scalar final : public PerfTest {
1✔
206
   public:
207
      void go(const PerfConfig& config) override {
1✔
208
         const auto run = config.runtime();
1✔
209
         auto& rng = config.rng();
1✔
210

211
         for(const auto& group_name : config.ecc_groups()) {
7✔
212
            const auto group = Botan::EC_Group::from_name(group_name);
6✔
213

214
            auto scalar_add_timer = config.make_timer(group_name + " scalar add");
12✔
215
            auto scalar_mul_timer = config.make_timer(group_name + " scalar mul");
12✔
216
            auto scalar_redc_timer = config.make_timer(group_name + " scalar redc");
12✔
217
            auto scalar_inv_timer = config.make_timer(group_name + " scalar inversion");
12✔
218
            auto scalar_inv_vt_timer = config.make_timer(group_name + " scalar inversion vartime");
12✔
219

220
            while(scalar_inv_timer->under(run)) {
74✔
221
               const auto rnd1 = rng.random_vec(group.get_order_bytes() * 2);
68✔
222
               const auto rnd2 = rng.random_vec(group.get_order_bytes() * 2);
68✔
223

224
               const auto s1 =
68✔
225
                  scalar_redc_timer->run([&]() { return Botan::EC_Scalar::from_bytes_mod_order(group, rnd1); });
136✔
226
               const auto s2 =
68✔
227
                  scalar_redc_timer->run([&]() { return Botan::EC_Scalar::from_bytes_mod_order(group, rnd2); });
136✔
228

229
               const auto sum1 = scalar_add_timer->run([&]() { return s1 + s2; });
204✔
230
               const auto sum2 = scalar_add_timer->run([&]() { return s2 + s1; });
204✔
231
               BOTAN_ASSERT_NOMSG(sum1 == sum2);
68✔
232

233
               const auto s1_inv = scalar_inv_timer->run([&]() { return s1.invert(); });
136✔
234
               const auto s1_inv_vt = scalar_inv_vt_timer->run([&]() { return s1.invert_vartime(); });
136✔
235
               BOTAN_ASSERT_NOMSG(s1_inv == s1_inv_vt);
68✔
236

237
               const auto s2_inv = scalar_inv_timer->run([&]() { return s2.invert(); });
136✔
238
               const auto s2_inv_vt = scalar_inv_vt_timer->run([&]() { return s2.invert_vartime(); });
136✔
239
               BOTAN_ASSERT_NOMSG(s2_inv == s2_inv_vt);
68✔
240

241
               const auto p1 = scalar_mul_timer->run([&]() { return s1 * s2; });
204✔
242
               const auto p2 = scalar_mul_timer->run([&]() { return s2 * s1; });
204✔
243
               BOTAN_ASSERT_NOMSG(p1 == p2);
68✔
244

245
               const auto c1 = scalar_mul_timer->run([&]() { return p1 * s1_inv; });
204✔
246
               BOTAN_ASSERT_NOMSG(c1 == s2);
68✔
247
               const auto c2 = scalar_mul_timer->run([&]() { return p2 * s1_inv_vt; });
204✔
248
               BOTAN_ASSERT_NOMSG(c2 == s2);
68✔
249
            }
204✔
250

251
            config.record_result(*scalar_add_timer);
6✔
252
            config.record_result(*scalar_mul_timer);
6✔
253
            config.record_result(*scalar_redc_timer);
6✔
254
            config.record_result(*scalar_inv_timer);
6✔
255
            config.record_result(*scalar_inv_vt_timer);
12✔
256
         }
24✔
257
      }
1✔
258
};
259

260
BOTAN_REGISTER_PERF_TEST("ecc_scalar", PerfTest_EllipticCurve_Scalar);
1✔
261

262
#endif
263

264
}  // namespace
265

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

© 2026 Coveralls, Inc