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

randombit / botan / 10329059925

10 Aug 2024 04:49AM UTC coverage: 91.276% (-0.02%) from 91.298%
10329059925

push

github

web-flow
Merge pull request #4143 from randombit/jack/bridge-pcurves-and-ec

Bridge pcurves into the main elliptic curve arithmetic

87809 of 96202 relevant lines covered (91.28%)

9299919.33 hits per line

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

93.55
/src/lib/pubkey/ec_group/ec_inner_data.cpp
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_bn.h>
11
#include <botan/internal/ec_inner_pc.h>
12
#include <botan/internal/pcurves.h>
13
#include <botan/internal/point_mul.h>
14

15
namespace Botan {
16

17
EC_Group_Data::EC_Group_Data(const BigInt& p,
1,120✔
18
                             const BigInt& a,
19
                             const BigInt& b,
20
                             const BigInt& g_x,
21
                             const BigInt& g_y,
22
                             const BigInt& order,
23
                             const BigInt& cofactor,
24
                             const OID& oid,
25
                             EC_Group_Source source) :
1,120✔
26
      m_curve(p, a, b),
1,120✔
27
      m_base_point(m_curve, g_x, g_y),
2,240✔
28
      m_g_x(g_x),
1,119✔
29
      m_g_y(g_y),
1,119✔
30
      m_order(order),
1,119✔
31
      m_cofactor(cofactor),
1,119✔
32
      m_mod_order(order),
1,119✔
33
      m_oid(oid),
1,119✔
34
      m_p_bits(p.bits()),
1,119✔
35
      m_order_bits(order.bits()),
1,119✔
36
      m_order_bytes((m_order_bits + 7) / 8),
1,119✔
37
      m_a_is_minus_3(a == p - 3),
2,238✔
38
      m_a_is_zero(a.is_zero()),
1,119✔
39
      m_has_cofactor(m_cofactor != 1),
1,119✔
40
      m_order_is_less_than_p(m_order < p),
1,119✔
41
      m_source(source) {
2,239✔
42
   if(!m_oid.empty()) {
1,119✔
43
      DER_Encoder der(m_der_named_curve);
1,107✔
44
      der.encode(m_oid);
1,107✔
45

46
      if(const auto id = PCurve::PrimeOrderCurveId::from_oid(m_oid)) {
1,107✔
47
         m_pcurve = PCurve::PrimeOrderCurve::from_id(*id);
867✔
48
         // still possibly null, if the curve is supported in general but not
49
         // available in the build
50
      }
51
   }
1,107✔
52

53
   if(!m_pcurve) {
1,119✔
54
      m_base_mult = std::make_unique<EC_Point_Base_Point_Precompute>(m_base_point, m_mod_order);
252✔
55
   }
56
}
1,121✔
57

58
bool EC_Group_Data::params_match(const BigInt& p,
939✔
59
                                 const BigInt& a,
60
                                 const BigInt& b,
61
                                 const BigInt& g_x,
62
                                 const BigInt& g_y,
63
                                 const BigInt& order,
64
                                 const BigInt& cofactor) const {
65
   return (this->p() == p && this->a() == a && this->b() == b && this->order() == order &&
1,133✔
66
           this->cofactor() == cofactor && this->g_x() == g_x && this->g_y() == g_y);
1,027✔
67
}
68

69
bool EC_Group_Data::params_match(const EC_Group_Data& other) const {
21✔
70
   return params_match(other.p(), other.a(), other.b(), other.g_x(), other.g_y(), other.order(), other.cofactor());
21✔
71
}
72

73
void EC_Group_Data::set_oid(const OID& oid) {
6✔
74
   BOTAN_ARG_CHECK(!oid.empty(), "OID should be set");
6✔
75
   BOTAN_STATE_CHECK(m_oid.empty() && m_der_named_curve.empty());
6✔
76
   m_oid = oid;
6✔
77

78
   DER_Encoder der(m_der_named_curve);
6✔
79
   der.encode(m_oid);
6✔
80
}
6✔
81

82
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_with_trunc(std::span<const uint8_t> bytes) const {
26,044✔
83
   const size_t bit_length = 8 * bytes.size();
26,044✔
84

85
   if(bit_length < order_bits()) {
26,044✔
86
      // No shifting required, but might still need to reduce by modulus
87
      return this->scalar_from_bytes_mod_order(bytes);
5,237✔
88
   } else {
89
      const size_t shift = bit_length - order_bits();
20,807✔
90

91
      const size_t new_length = bytes.size() - (shift / 8);
20,807✔
92
      const size_t bit_shift = shift % 8;
20,807✔
93

94
      if(bit_shift == 0) {
20,807✔
95
         // Easy case just read different bytes
96
         return this->scalar_from_bytes_mod_order(bytes.first(new_length));
18,173✔
97
      } else {
98
         std::vector<uint8_t> sbytes(new_length);
2,634✔
99

100
         uint8_t carry = 0;
2,634✔
101
         for(size_t i = 0; i != new_length; ++i) {
71,917✔
102
            const uint8_t w = bytes[i];
69,283✔
103
            sbytes[i] = (w >> bit_shift) | carry;
69,283✔
104
            carry = w << (8 - bit_shift);
69,283✔
105
         }
106

107
         return this->scalar_from_bytes_mod_order(sbytes);
2,634✔
108
      }
2,634✔
109
   }
110
}
111

112
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_mod_order(std::span<const uint8_t> bytes) const {
26,794✔
113
   if(bytes.size() >= 2 * order_bytes()) {
26,794✔
114
      return {};
×
115
   }
116

117
   if(m_pcurve) {
26,794✔
118
      if(auto s = m_pcurve->scalar_from_wide_bytes(bytes)) {
19,793✔
119
         return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), std::move(*s));
19,793✔
120
      } else {
121
         return {};
×
122
      }
19,793✔
123
   } else {
124
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), mod_order(BigInt(bytes)));
21,003✔
125
   }
126
}
127

128
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_random(RandomNumberGenerator& rng) const {
7,330✔
129
   if(m_pcurve) {
7,330✔
130
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->random_scalar(rng));
3,564✔
131
   } else {
132
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(),
7,532✔
133
                                                 BigInt::random_integer(rng, BigInt::one(), m_order));
15,064✔
134
   }
135
}
136

137
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_zero() const {
×
138
   if(m_pcurve) {
×
139
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_zero());
×
140
   } else {
141
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::zero());
×
142
   }
143
}
144

145
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_one() const {
50✔
146
   if(m_pcurve) {
50✔
147
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_one());
42✔
148
   } else {
149
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::one());
8✔
150
   }
151
}
152

153
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bigint(const BigInt& bn) const {
4,799✔
154
   if(bn <= 0 || bn >= m_order) {
4,799✔
155
      return {};
×
156
   }
157

158
   if(m_pcurve) {
4,799✔
159
      return this->scalar_deserialize(bn.serialize(m_order_bytes));
8,518✔
160
   } else {
161
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), bn);
540✔
162
   }
163
}
164

165
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::gk_x_mod_order(const EC_Scalar_Data& scalar,
3,305✔
166
                                                              RandomNumberGenerator& rng,
167
                                                              std::vector<BigInt>& ws) const {
168
   if(m_pcurve) {
3,305✔
169
      const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
1,684✔
170
      auto gk_x_mod_order = m_pcurve->base_point_mul_x_mod_order(k.value(), rng);
1,684✔
171
      return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), gk_x_mod_order);
1,684✔
172
   } else {
1,684✔
173
      const auto& k = EC_Scalar_Data_BN::checked_ref(scalar);
1,621✔
174
      BOTAN_STATE_CHECK(m_base_mult != nullptr);
1,621✔
175
      const auto pt = m_base_mult->mul(k.value(), rng, m_order, ws);
1,621✔
176

177
      if(pt.is_zero()) {
3,242✔
178
         return scalar_zero();
×
179
      } else {
180
         return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), mod_order(pt.get_affine_x()));
4,863✔
181
      }
182
   }
1,621✔
183
}
184

185
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_deserialize(std::span<const uint8_t> bytes) const {
64,146✔
186
   if(bytes.size() != m_order_bytes) {
64,146✔
187
      return nullptr;
6,558✔
188
   }
189

190
   if(m_pcurve) {
57,588✔
191
      if(auto s = m_pcurve->deserialize_scalar(bytes)) {
44,309✔
192
         return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), *s);
42,160✔
193
      } else {
194
         return nullptr;
2,149✔
195
      }
44,309✔
196
   } else {
197
      BigInt r(bytes);
13,279✔
198

199
      if(r.is_zero() || r >= m_order) {
26,558✔
200
         return nullptr;
751✔
201
      }
202

203
      return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), std::move(r));
12,528✔
204
   }
13,279✔
205
}
206

207
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_deserialize(std::span<const uint8_t> bytes) const {
25,640✔
208
   try {
25,640✔
209
      if(m_pcurve) {
25,640✔
210
         if(auto pt = m_pcurve->deserialize_point(bytes)) {
20,421✔
211
            return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(*pt));
20,250✔
212
         } else {
213
            return nullptr;
171✔
214
         }
20,421✔
215
      } else {
216
         auto pt = Botan::OS2ECP(bytes.data(), bytes.size(), curve());
5,219✔
217
         return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
5,194✔
218
      }
5,194✔
219
   } catch(...) {
25✔
220
      return nullptr;
25✔
221
   }
25✔
222
}
223

224
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_ro(std::string_view hash_fn,
32✔
225
                                                                           std::span<const uint8_t> input,
226
                                                                           std::span<const uint8_t> domain_sep) const {
227
   if(m_pcurve) {
32✔
228
      auto pt = m_pcurve->hash_to_curve_ro(hash_fn, input, domain_sep);
32✔
229
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt.to_affine());
32✔
230
   } else {
32✔
231
      throw Not_Implemented("Hash to curve is not implemented for this curve");
×
232
   }
233
}
234

235
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_nu(std::string_view hash_fn,
35✔
236
                                                                           std::span<const uint8_t> input,
237
                                                                           std::span<const uint8_t> domain_sep) const {
238
   if(m_pcurve) {
35✔
239
      auto pt = m_pcurve->hash_to_curve_nu(hash_fn, input, domain_sep);
35✔
240
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
35✔
241
   } else {
35✔
242
      throw Not_Implemented("Hash to curve is not implemented for this curve");
×
243
   }
244
}
245

246
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_g_mul(const EC_Scalar_Data& scalar,
8,524✔
247
                                                                RandomNumberGenerator& rng,
248
                                                                std::vector<BigInt>& ws) const {
249
   if(m_pcurve) {
8,524✔
250
      const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
5,212✔
251
      auto pt = m_pcurve->mul_by_g(k.value(), rng).to_affine();
10,424✔
252
      return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
5,212✔
253
   } else {
5,212✔
254
      const auto& group = scalar.group();
3,312✔
255
      const auto& bn = EC_Scalar_Data_BN::checked_ref(scalar);
3,312✔
256

257
      BOTAN_STATE_CHECK(group->m_base_mult != nullptr);
3,312✔
258
      auto pt = group->m_base_mult->mul(bn.value(), rng, m_order, ws);
3,312✔
259
      return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
3,312✔
260
   }
3,312✔
261
}
262

263
std::unique_ptr<EC_Mul2Table_Data> EC_Group_Data::make_mul2_table(const EC_AffinePoint_Data& h) const {
11,573✔
264
   if(m_pcurve) {
11,573✔
265
      EC_AffinePoint_Data_PC g(shared_from_this(), m_pcurve->generator());
20,792✔
266
      return std::make_unique<EC_Mul2Table_Data_PC>(g, h);
10,396✔
267
   } else {
10,396✔
268
      EC_AffinePoint_Data_BN g(shared_from_this(), this->base_point());
2,354✔
269
      return std::make_unique<EC_Mul2Table_Data_BN>(g, h);
1,177✔
270
   }
1,177✔
271
}
272

273
}  // 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

© 2025 Coveralls, Inc