Botan 3.6.0
Crypto and TLS for C&
ec_inner_data.cpp
Go to the documentation of this file.
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
15namespace Botan {
16
18
20 const BigInt& a,
21 const BigInt& b,
22 const BigInt& g_x,
23 const BigInt& g_y,
24 const BigInt& order,
25 const BigInt& cofactor,
26 const OID& oid,
27 EC_Group_Source source) :
28 m_curve(p, a, b),
29 m_base_point(m_curve, g_x, g_y),
30 m_g_x(g_x),
31 m_g_y(g_y),
32 m_order(order),
33 m_cofactor(cofactor),
34 m_mod_order(order),
35 m_oid(oid),
36 m_p_bits(p.bits()),
37 m_order_bits(order.bits()),
38 m_order_bytes((m_order_bits + 7) / 8),
39 m_a_is_minus_3(a == p - 3),
40 m_a_is_zero(a.is_zero()),
41 m_has_cofactor(m_cofactor != 1),
42 m_order_is_less_than_p(m_order < p),
43 m_source(source) {
44 if(!m_oid.empty()) {
45 DER_Encoder der(m_der_named_curve);
46 der.encode(m_oid);
47
48 if(const auto id = PCurve::PrimeOrderCurveId::from_oid(m_oid)) {
49 m_pcurve = PCurve::PrimeOrderCurve::from_id(*id);
50 // still possibly null, if the curve is supported in general but not
51 // available in the build
52 }
53 }
54
55 if(!m_pcurve) {
56 m_base_mult = std::make_unique<EC_Point_Base_Point_Precompute>(m_base_point, m_mod_order);
57 }
58}
59
60bool EC_Group_Data::params_match(const BigInt& p,
61 const BigInt& a,
62 const BigInt& b,
63 const BigInt& g_x,
64 const BigInt& g_y,
65 const BigInt& order,
66 const BigInt& cofactor) const {
67 return (this->p() == p && this->a() == a && this->b() == b && this->order() == order &&
68 this->cofactor() == cofactor && this->g_x() == g_x && this->g_y() == g_y);
69}
70
71bool EC_Group_Data::params_match(const EC_Group_Data& other) const {
72 return params_match(other.p(), other.a(), other.b(), other.g_x(), other.g_y(), other.order(), other.cofactor());
73}
74
75void EC_Group_Data::set_oid(const OID& oid) {
76 BOTAN_ARG_CHECK(!oid.empty(), "OID should be set");
77 BOTAN_STATE_CHECK(m_oid.empty() && m_der_named_curve.empty());
78 m_oid = oid;
79
80 DER_Encoder der(m_der_named_curve);
81 der.encode(m_oid);
82}
83
84std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_with_trunc(std::span<const uint8_t> bytes) const {
85 const size_t bit_length = 8 * bytes.size();
86
87 if(bit_length < order_bits()) {
88 // No shifting required, but might still need to reduce by modulus
89 return this->scalar_from_bytes_mod_order(bytes);
90 } else {
91 const size_t shift = bit_length - order_bits();
92
93 const size_t new_length = bytes.size() - (shift / 8);
94 const size_t bit_shift = shift % 8;
95
96 if(bit_shift == 0) {
97 // Easy case just read different bytes
98 return this->scalar_from_bytes_mod_order(bytes.first(new_length));
99 } else {
100 std::vector<uint8_t> sbytes(new_length);
101
102 uint8_t carry = 0;
103 for(size_t i = 0; i != new_length; ++i) {
104 const uint8_t w = bytes[i];
105 sbytes[i] = (w >> bit_shift) | carry;
106 carry = w << (8 - bit_shift);
107 }
108
109 return this->scalar_from_bytes_mod_order(sbytes);
110 }
111 }
112}
113
114std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_mod_order(std::span<const uint8_t> bytes) const {
115 if(bytes.size() >= 2 * order_bytes()) {
116 return {};
117 }
118
119 if(m_pcurve) {
120 if(auto s = m_pcurve->scalar_from_wide_bytes(bytes)) {
121 return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), std::move(*s));
122 } else {
123 return {};
124 }
125 } else {
126 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), mod_order(BigInt(bytes)));
127 }
128}
129
130std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_random(RandomNumberGenerator& rng) const {
131 if(m_pcurve) {
132 return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->random_scalar(rng));
133 } else {
134 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(),
135 BigInt::random_integer(rng, BigInt::one(), m_order));
136 }
137}
138
139std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_zero() const {
140 if(m_pcurve) {
141 return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_zero());
142 } else {
143 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::zero());
144 }
145}
146
147std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_one() const {
148 if(m_pcurve) {
149 return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_one());
150 } else {
151 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::one());
152 }
153}
154
155std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bigint(const BigInt& bn) const {
156 if(bn <= 0 || bn >= m_order) {
157 return {};
158 }
159
160 if(m_pcurve) {
161 return this->scalar_deserialize(bn.serialize(m_order_bytes));
162 } else {
163 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), bn);
164 }
165}
166
167std::unique_ptr<EC_Scalar_Data> EC_Group_Data::gk_x_mod_order(const EC_Scalar_Data& scalar,
169 std::vector<BigInt>& ws) const {
170 if(m_pcurve) {
171 const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
172 auto gk_x_mod_order = m_pcurve->base_point_mul_x_mod_order(k.value(), rng);
173 return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), gk_x_mod_order);
174 } else {
175 const auto& k = EC_Scalar_Data_BN::checked_ref(scalar);
176 BOTAN_STATE_CHECK(m_base_mult != nullptr);
177 const auto pt = m_base_mult->mul(k.value(), rng, m_order, ws);
178
179 if(pt.is_zero()) {
180 return scalar_zero();
181 } else {
182 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), mod_order(pt.get_affine_x()));
183 }
184 }
185}
186
187std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_deserialize(std::span<const uint8_t> bytes) const {
188 if(bytes.size() != m_order_bytes) {
189 return nullptr;
190 }
191
192 if(m_pcurve) {
193 if(auto s = m_pcurve->deserialize_scalar(bytes)) {
194 return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), *s);
195 } else {
196 return nullptr;
197 }
198 } else {
199 BigInt r(bytes);
200
201 if(r.is_zero() || r >= m_order) {
202 return nullptr;
203 }
204
205 return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), std::move(r));
206 }
207}
208
209std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_deserialize(std::span<const uint8_t> bytes) const {
210 try {
211 if(m_pcurve) {
212 if(auto pt = m_pcurve->deserialize_point(bytes)) {
213 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(*pt));
214 } else {
215 return nullptr;
216 }
217 } else {
218 auto pt = Botan::OS2ECP(bytes.data(), bytes.size(), curve());
219 return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
220 }
221 } catch(...) {
222 return nullptr;
223 }
224}
225
226std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_ro(std::string_view hash_fn,
227 std::span<const uint8_t> input,
228 std::span<const uint8_t> domain_sep) const {
229 if(m_pcurve) {
230 auto pt = m_pcurve->hash_to_curve_ro(hash_fn, input, domain_sep);
231 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt.to_affine());
232 } else {
233 throw Not_Implemented("Hash to curve is not implemented for this curve");
234 }
235}
236
237std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_nu(std::string_view hash_fn,
238 std::span<const uint8_t> input,
239 std::span<const uint8_t> domain_sep) const {
240 if(m_pcurve) {
241 auto pt = m_pcurve->hash_to_curve_nu(hash_fn, input, domain_sep);
242 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
243 } else {
244 throw Not_Implemented("Hash to curve is not implemented for this curve");
245 }
246}
247
248std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_g_mul(const EC_Scalar_Data& scalar,
250 std::vector<BigInt>& ws) const {
251 if(m_pcurve) {
252 const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
253 auto pt = m_pcurve->mul_by_g(k.value(), rng).to_affine();
254 return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
255 } else {
256 const auto& group = scalar.group();
257 const auto& bn = EC_Scalar_Data_BN::checked_ref(scalar);
258
259 BOTAN_STATE_CHECK(group->m_base_mult != nullptr);
260 auto pt = group->m_base_mult->mul(bn.value(), rng, m_order, ws);
261 return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
262 }
263}
264
265std::unique_ptr<EC_Mul2Table_Data> EC_Group_Data::make_mul2_table(const EC_AffinePoint_Data& h) const {
266 if(m_pcurve) {
267 EC_AffinePoint_Data_PC g(shared_from_this(), m_pcurve->generator());
268 return std::make_unique<EC_Mul2Table_Data_PC>(g, h);
269 } else {
270 EC_AffinePoint_Data_BN g(shared_from_this(), this->base_point());
271 return std::make_unique<EC_Mul2Table_Data_BN>(g, h);
272 }
273}
274
275} // namespace Botan
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:41
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
bool is_zero() const
Definition bigint.h:458
T serialize(size_t len) const
Definition bigint.h:712
DER_Encoder & encode(bool b)
Definition der_enc.cpp:250
const BigInt & p() const
const BigInt & g_x() const
const BigInt & a() const
EC_Group_Data(const BigInt &p, const BigInt &a, const BigInt &b, const BigInt &g_x, const BigInt &g_y, const BigInt &order, const BigInt &cofactor, const OID &oid, EC_Group_Source source)
const BigInt & cofactor() const
const BigInt & g_y() const
const BigInt & b() const
const BigInt & order() const
virtual const std::shared_ptr< const EC_Group_Data > & group() const =0
bool empty() const
Definition asn1_obj.h:266
EC_Group_Source
Definition ec_group.h:36
EC_Point OS2ECP(const uint8_t data[], size_t data_len, const CurveGFp &curve)
Definition ec_point.cpp:648
void carry(int64_t &h0, int64_t &h1)
const SIMD_8x32 & b