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

randombit / botan / 19012754211

02 Nov 2025 01:10PM UTC coverage: 90.677% (+0.006%) from 90.671%
19012754211

push

github

web-flow
Merge pull request #5137 from randombit/jack/clang-tidy-includes

Remove various unused includes flagged by clang-tidy misc-include-cleaner

100457 of 110786 relevant lines covered (90.68%)

12189873.8 hits per line

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

95.42
/src/lib/pubkey/sm2/sm2.cpp
1
/*
2
* SM2 Signatures
3
* (C) 2017,2018 Ribose Inc
4
* (C) 2018,2024 Jack Lloyd
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#include <botan/sm2.h>
10

11
#include <botan/hash.h>
12
#include <botan/internal/keypair.h>
13
#include <botan/internal/loadstor.h>
14
#include <botan/internal/pk_ops_impl.h>
15

16
namespace Botan {
17

18
std::string SM2_PublicKey::algo_name() const {
207✔
19
   return "SM2";
207✔
20
}
21

22
std::unique_ptr<Public_Key> SM2_PrivateKey::public_key() const {
24✔
23
   return std::make_unique<SM2_Signature_PublicKey>(domain(), _public_ec_point());
24✔
24
}
25

26
bool SM2_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const {
4✔
27
   if(!EC_PrivateKey::check_key(rng, strong)) {
4✔
28
      return false;
29
   }
30

31
   // SM2 has an oddity in private key generation when compared to
32
   // other EC*DSA style signature algorithms described in ISO14888-3:
33
   // the private key x MUST be in [0, q-1) instead of [0, q).
34
   //
35
   // The lower bound is already checked by the default impl
36
   if(private_value() >= domain().get_order() - 1) {
4✔
37
      return false;
38
   }
39

40
   if(!strong) {
4✔
41
      return true;
42
   }
43

44
   return KeyPair::signature_consistency_check(rng, *this, "user@example.com,SM3");
2✔
45
}
46

47
SM2_PrivateKey::SM2_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) :
20✔
48
      EC_PrivateKey(alg_id, key_bits),
49
      m_da_inv((this->_private_key() + EC_Scalar::one(domain())).invert()),
20✔
50
      m_da_inv_legacy(m_da_inv.to_bigint()) {}
40✔
51

52
SM2_PrivateKey::SM2_PrivateKey(EC_Group group, EC_Scalar x) :
×
53
      EC_PrivateKey(std::move(group), std::move(x)),
54
      m_da_inv((this->_private_key() + EC_Scalar::one(domain())).invert()),
×
55
      m_da_inv_legacy(m_da_inv.to_bigint()) {}
×
56

57
SM2_PrivateKey::SM2_PrivateKey(RandomNumberGenerator& rng, EC_Group group) :
10✔
58
      EC_PrivateKey(rng, std::move(group)),
59
      m_da_inv((this->_private_key() + EC_Scalar::one(domain())).invert()),
10✔
60
      m_da_inv_legacy(m_da_inv.to_bigint()) {}
20✔
61

62
SM2_PrivateKey::SM2_PrivateKey(RandomNumberGenerator& rng, EC_Group group, const BigInt& x) :
15✔
63
      EC_PrivateKey(rng, std::move(group), x),
64
      m_da_inv((this->_private_key() + EC_Scalar::one(domain())).invert()),
15✔
65
      m_da_inv_legacy(m_da_inv.to_bigint()) {}
30✔
66

67
std::vector<uint8_t> sm2_compute_za(HashFunction& hash,
64✔
68
                                    std::string_view user_id,
69
                                    const EC_Group& group,
70
                                    const EC_AffinePoint& pubkey) {
71
   if(user_id.size() >= 8192) {
64✔
72
      throw Invalid_Argument("SM2 user id too long to represent");
×
73
   }
74

75
   const uint16_t uid_len = static_cast<uint16_t>(8 * user_id.size());
64✔
76

77
   hash.update(get_byte<0>(uid_len));
64✔
78
   hash.update(get_byte<1>(uid_len));
64✔
79
   hash.update(user_id);
64✔
80

81
   const size_t p_bytes = group.get_p_bytes();
64✔
82

83
   hash.update(group.get_a().serialize(p_bytes));
64✔
84
   hash.update(group.get_b().serialize(p_bytes));
64✔
85
   hash.update(group.get_g_x().serialize(p_bytes));
64✔
86
   hash.update(group.get_g_y().serialize(p_bytes));
64✔
87
   hash.update(pubkey.xy_bytes());
64✔
88

89
   return hash.final<std::vector<uint8_t>>();
64✔
90
}
91

92
namespace {
93

94
/**
95
* SM2 signature operation
96
*/
97
class SM2_Signature_Operation final : public PK_Ops::Signature {
×
98
   public:
99
      SM2_Signature_Operation(const SM2_PrivateKey& sm2, std::string_view ident, std::string_view hash) :
33✔
100
            m_group(sm2.domain()), m_x(sm2._private_key()), m_da_inv(sm2._get_da_inv()) {
33✔
101
         if(hash == "Raw") {
35✔
102
            // m_hash is null, m_za is empty
103
         } else {
104
            m_hash = HashFunction::create_or_throw(hash);
31✔
105
            // ZA=H256(ENTLA || IDA || a || b || xG || yG || xA || yA)
106
            m_za = sm2_compute_za(*m_hash, ident, m_group, sm2._public_ec_point());
31✔
107
            m_hash->update(m_za);
31✔
108
         }
109
      }
33✔
110

111
      size_t signature_length() const override { return 2 * m_group.get_order_bytes(); }
28✔
112

113
      void update(std::span<const uint8_t> input) override {
44✔
114
         if(m_hash) {
44✔
115
            m_hash->update(input);
42✔
116
         } else {
117
            m_digest.insert(m_digest.end(), input.begin(), input.end());
2✔
118
         }
119
      }
44✔
120

121
      std::vector<uint8_t> sign(RandomNumberGenerator& rng) override;
122

123
      std::string hash_function() const override { return m_hash ? m_hash->name() : "Raw"; }
4✔
124

125
   private:
126
      const EC_Group m_group;
127
      const EC_Scalar m_x;
128
      const EC_Scalar m_da_inv;
129

130
      std::vector<uint8_t> m_za;
131
      secure_vector<uint8_t> m_digest;
132
      std::unique_ptr<HashFunction> m_hash;
133
};
134

135
std::vector<uint8_t> SM2_Signature_Operation::sign(RandomNumberGenerator& rng) {
39✔
136
   const auto e = [&]() {
117✔
137
      if(m_hash) {
39✔
138
         auto ie = EC_Scalar::from_bytes_mod_order(m_group, m_hash->final());
37✔
139
         // prepend ZA for next signature if any
140
         m_hash->update(m_za);
37✔
141
         return ie;
37✔
142
      } else {
37✔
143
         auto ie = EC_Scalar::from_bytes_mod_order(m_group, m_digest);
2✔
144
         m_digest.clear();
2✔
145
         return ie;
2✔
146
      }
2✔
147
   }();
39✔
148

149
   const auto k = EC_Scalar::random(m_group, rng);
39✔
150

151
   const auto r = EC_Scalar::gk_x_mod_order(k, rng) + e;
78✔
152
   const auto s = (k - r * m_x) * m_da_inv;
39✔
153

154
   return EC_Scalar::serialize_pair(r, s);
78✔
155
}
39✔
156

157
/**
158
* SM2 verification operation
159
*/
160
class SM2_Verification_Operation final : public PK_Ops::Verification {
×
161
   public:
162
      SM2_Verification_Operation(const SM2_PublicKey& sm2, std::string_view ident, std::string_view hash) :
33✔
163
            m_group(sm2.domain()), m_gy_mul(sm2._public_ec_point()) {
33✔
164
         if(hash == "Raw") {
35✔
165
            // m_hash is null, m_za is empty
166
         } else {
167
            m_hash = HashFunction::create_or_throw(hash);
31✔
168
            // ZA=H256(ENTLA || IDA || a || b || xG || yG || xA || yA)
169
            m_za = sm2_compute_za(*m_hash, ident, m_group, sm2._public_ec_point());
31✔
170
            m_hash->update(m_za);
31✔
171
         }
172
      }
33✔
173

174
      void update(std::span<const uint8_t> input) override {
196✔
175
         if(m_hash) {
196✔
176
            m_hash->update(input);
172✔
177
         } else {
178
            m_digest.insert(m_digest.end(), input.begin(), input.end());
24✔
179
         }
180
      }
196✔
181

182
      bool is_valid_signature(std::span<const uint8_t> sig) override;
183

184
      std::string hash_function() const override { return m_hash ? m_hash->name() : "Raw"; }
4✔
185

186
   private:
187
      const EC_Group m_group;
188
      const EC_Group::Mul2Table m_gy_mul;
189
      secure_vector<uint8_t> m_digest;
190
      std::vector<uint8_t> m_za;
191
      std::unique_ptr<HashFunction> m_hash;
192
};
193

194
bool SM2_Verification_Operation::is_valid_signature(std::span<const uint8_t> sig) {
211✔
195
   const auto e = [&]() {
633✔
196
      if(m_hash) {
211✔
197
         auto ie = EC_Scalar::from_bytes_mod_order(m_group, m_hash->final());
187✔
198
         // prepend ZA for next signature if any
199
         m_hash->update(m_za);
187✔
200
         return ie;
187✔
201
      } else {
187✔
202
         auto ie = EC_Scalar::from_bytes_mod_order(m_group, m_digest);
24✔
203
         m_digest.clear();
24✔
204
         return ie;
24✔
205
      }
24✔
206
   }();
211✔
207

208
   if(auto rs = EC_Scalar::deserialize_pair(m_group, sig)) {
211✔
209
      const auto& [r, s] = rs.value();
192✔
210

211
      if(r.is_nonzero() && s.is_nonzero()) {
381✔
212
         const auto t = r + s;
189✔
213
         if(t.is_nonzero()) {
189✔
214
            // Check if r - e = x_coord(g*s + y*t) % n
215
            return m_gy_mul.mul2_vartime_x_mod_order_eq(r - e, s, t);
189✔
216
         }
217
      }
189✔
218
   }
189✔
219
   return false;
22✔
220
}
211✔
221

222
void parse_sm2_param_string(std::string_view params, std::string& userid, std::string& hash) {
66✔
223
   // GM/T 0009-2012 specifies this as the default userid
224
   const std::string default_userid = "1234567812345678";
66✔
225

226
   // defaults:
227
   userid = default_userid;
66✔
228
   hash = "SM3";
66✔
229

230
   /*
231
   * SM2 parameters have the following possible formats:
232
   * Ident [since 2.2.0]
233
   * Ident,Hash [since 2.3.0]
234
   */
235

236
   auto comma = params.find(',');
66✔
237
   if(comma == std::string::npos) {
66✔
238
      userid = params;
110✔
239
   } else {
240
      userid = params.substr(0, comma);
22✔
241
      hash = params.substr(comma + 1, std::string::npos);
44✔
242
   }
243
}
66✔
244

245
}  // namespace
246

247
std::unique_ptr<Private_Key> SM2_PublicKey::generate_another(RandomNumberGenerator& rng) const {
2✔
248
   return std::make_unique<SM2_PrivateKey>(rng, domain());
4✔
249
}
250

251
std::unique_ptr<PK_Ops::Verification> SM2_PublicKey::create_verification_op(std::string_view params,
54✔
252
                                                                            std::string_view provider) const {
253
   if(provider == "base" || provider.empty()) {
63✔
254
      std::string userid;
33✔
255
      std::string hash;
33✔
256
      parse_sm2_param_string(params, userid, hash);
33✔
257
      return std::make_unique<SM2_Verification_Operation>(*this, userid, hash);
33✔
258
   }
33✔
259

260
   throw Provider_Not_Found(algo_name(), provider);
42✔
261
}
262

263
std::unique_ptr<PK_Ops::Signature> SM2_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/,
54✔
264
                                                                       std::string_view params,
265
                                                                       std::string_view provider) const {
266
   if(provider == "base" || provider.empty()) {
63✔
267
      std::string userid;
33✔
268
      std::string hash;
33✔
269
      parse_sm2_param_string(params, userid, hash);
33✔
270
      return std::make_unique<SM2_Signature_Operation>(*this, userid, hash);
33✔
271
   }
33✔
272

273
   throw Provider_Not_Found(algo_name(), provider);
42✔
274
}
275

276
}  // namespace Botan
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

© 2026 Coveralls, Inc