Botan 3.7.1
Crypto and TLS for C&
ec_apoint.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/ec_apoint.h>
8
9#include <botan/ec_group.h>
10#include <botan/ec_scalar.h>
11#include <botan/internal/ec_inner_data.h>
12
13namespace Botan {
14
15EC_AffinePoint::EC_AffinePoint(std::unique_ptr<EC_AffinePoint_Data> point) : m_point(std::move(point)) {
16 BOTAN_ASSERT_NONNULL(m_point);
17}
18
19EC_AffinePoint::EC_AffinePoint(const EC_AffinePoint& other) : m_point(other.inner().clone()) {}
20
21EC_AffinePoint::EC_AffinePoint(EC_AffinePoint&& other) noexcept : m_point(std::move(other.m_point)) {}
22
24 if(this != &other) {
25 m_point = other.inner().clone();
26 }
27 return (*this);
28}
29
31 m_point.swap(other.m_point);
32 return (*this);
33}
34
35EC_AffinePoint::EC_AffinePoint(const EC_Group& group, std::span<const uint8_t> bytes) {
36 m_point = group._data()->point_deserialize(bytes);
37 if(!m_point) {
38 throw Decoding_Error("Failed to deserialize elliptic curve point");
39 }
40}
41
42#if defined(BOTAN_HAS_LEGACY_EC_POINT)
43
44EC_Point EC_AffinePoint::to_legacy_point() const {
45 return m_point->to_legacy_point();
46}
47
48EC_AffinePoint::EC_AffinePoint(const EC_Group& group, const EC_Point& pt) :
49 EC_AffinePoint(group, pt.encode(EC_Point_Format::Uncompressed)) {}
50
51#endif
52
54 if(this == &other) {
55 return true;
56 }
57
58 // We are relying on EC_Group to ensure there is just a single shared_ptr
59 // for any set of group params
60 if(this->_group() != other._group()) {
61 return false;
62 }
63
64 auto a_is_id = this->is_identity();
65 auto b_is_id = other.is_identity();
66
67 if(a_is_id || b_is_id) {
68 return (a_is_id == b_is_id);
69 }
70
71 auto a_xy = this->serialize_uncompressed();
72 auto b_xy = other.serialize_uncompressed();
73 BOTAN_ASSERT_NOMSG(a_xy.size() == b_xy.size());
74
75 return CT::is_equal(a_xy.data(), b_xy.data(), a_xy.size()).as_bool();
76}
77
79 const uint8_t id_encoding[1] = {0};
80 return EC_AffinePoint(group, id_encoding);
81}
82
84 // TODO it would be nice to improve this (pcurves supports returning generator directly)
85 try {
86 return EC_AffinePoint::from_bigint_xy(group, group.get_g_x(), group.get_g_y()).value();
87 } catch(...) {
88 throw Internal_Error("EC_AffinePoint::generator curve rejected generator");
89 }
90}
91
92std::optional<EC_AffinePoint> EC_AffinePoint::from_bigint_xy(const EC_Group& group, const BigInt& x, const BigInt& y) {
93 if(x.is_negative() || x >= group.get_p()) {
94 return {};
95 }
96 if(y.is_negative() || y >= group.get_p()) {
97 return {};
98 }
99
100 const size_t fe_bytes = group.get_p_bytes();
101 std::vector<uint8_t> sec1(1 + 2 * fe_bytes);
102 sec1[0] = 0x04;
103 x.serialize_to(std::span{sec1}.subspan(1, fe_bytes));
104 y.serialize_to(std::span{sec1}.last(fe_bytes));
105
106 return EC_AffinePoint::deserialize(group, sec1);
107}
108
110 return inner().field_element_bytes();
111}
112
114 return inner().is_identity();
115}
116
118 std::string_view hash_fn,
119 std::span<const uint8_t> input,
120 std::span<const uint8_t> domain_sep) {
121 auto pt = group._data()->point_hash_to_curve_ro(hash_fn, input, domain_sep);
122 return EC_AffinePoint(std::move(pt));
123}
124
126 std::string_view hash_fn,
127 std::span<const uint8_t> input,
128 std::span<const uint8_t> domain_sep) {
129 auto pt = group._data()->point_hash_to_curve_nu(hash_fn, input, domain_sep);
130 return EC_AffinePoint(std::move(pt));
131}
132
134
135std::optional<EC_AffinePoint> EC_AffinePoint::deserialize(const EC_Group& group, std::span<const uint8_t> bytes) {
136 if(auto pt = group._data()->point_deserialize(bytes)) {
137 return EC_AffinePoint(std::move(pt));
138 } else {
139 return {};
140 }
141}
142
143EC_AffinePoint EC_AffinePoint::g_mul(const EC_Scalar& scalar, RandomNumberGenerator& rng, std::vector<BigInt>& ws) {
144 auto pt = scalar._inner().group()->point_g_mul(scalar.inner(), rng, ws);
145 return EC_AffinePoint(std::move(pt));
146}
147
148EC_AffinePoint EC_AffinePoint::mul(const EC_Scalar& scalar, RandomNumberGenerator& rng, std::vector<BigInt>& ws) const {
149 return EC_AffinePoint(inner().mul(scalar._inner(), rng, ws));
150}
151
154 std::vector<BigInt>& ws) const {
155 return inner().mul_x_only(scalar._inner(), rng, ws);
156}
157
158std::optional<EC_AffinePoint> EC_AffinePoint::mul_px_qy(const EC_AffinePoint& p,
159 const EC_Scalar& x,
160 const EC_AffinePoint& q,
161 const EC_Scalar& y,
163 auto pt = p._inner().group()->mul_px_qy(p._inner(), x._inner(), q._inner(), y._inner(), rng);
164 if(pt) {
165 return EC_AffinePoint(std::move(pt));
166 } else {
167 return {};
168 }
169}
170
172 auto pt = _inner().group()->affine_add(_inner(), q._inner());
173 return EC_AffinePoint(std::move(pt));
174}
175
177 auto pt = this->_inner().group()->affine_neg(this->_inner());
178 return EC_AffinePoint(std::move(pt));
179}
180
181std::vector<uint8_t> EC_AffinePoint::serialize(EC_Point_Format format) const {
182 if(format == EC_Point_Format::Compressed) {
183 return this->serialize_compressed();
184 } else if(format == EC_Point_Format::Uncompressed) {
185 return this->serialize_uncompressed();
186 } else {
187 // The deprecated "hybrid" point encoding
188 // TODO(Botan4) Remove this
189 auto enc = this->serialize_uncompressed();
190 const bool y_is_odd = (enc[enc.size() - 1] & 0x01) == 0x01;
191 enc.front() = y_is_odd ? 0x07 : 0x06;
192 return enc;
193 }
194}
195
196void EC_AffinePoint::serialize_x_to(std::span<uint8_t> bytes) const {
198 m_point->serialize_x_to(bytes);
199}
200
201void EC_AffinePoint::serialize_y_to(std::span<uint8_t> bytes) const {
203 m_point->serialize_y_to(bytes);
204}
205
206void EC_AffinePoint::serialize_xy_to(std::span<uint8_t> bytes) const {
208 m_point->serialize_xy_to(bytes);
209}
210
211void EC_AffinePoint::serialize_compressed_to(std::span<uint8_t> bytes) const {
213 m_point->serialize_compressed_to(bytes);
214}
215
216void EC_AffinePoint::serialize_uncompressed_to(std::span<uint8_t> bytes) const {
218 m_point->serialize_uncompressed_to(bytes);
219}
220
221EC_AffinePoint EC_AffinePoint::_from_inner(std::unique_ptr<EC_AffinePoint_Data> inner) {
222 return EC_AffinePoint(std::move(inner));
223}
224
225const std::shared_ptr<const EC_Group_Data>& EC_AffinePoint::_group() const {
226 return inner().group();
227}
228
229} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:41
#define BOTAN_ASSERT_NONNULL(ptr)
Definition assert.h:86
void serialize_to(std::span< uint8_t > out) const
Definition bigint.cpp:383
bool is_negative() const
Definition bigint.h:560
virtual std::unique_ptr< EC_AffinePoint_Data > clone() const =0
virtual size_t field_element_bytes() const =0
virtual secure_vector< uint8_t > mul_x_only(const EC_Scalar_Data &scalar, RandomNumberGenerator &rng, std::vector< BigInt > &ws) const =0
virtual const std::shared_ptr< const EC_Group_Data > & group() const =0
virtual bool is_identity() const =0
static EC_AffinePoint hash_to_curve_ro(const EC_Group &group, std::string_view hash_fn, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep)
EC_AffinePoint negate() const
Point negation.
size_t field_element_bytes() const
void serialize_xy_to(std::span< uint8_t > bytes) const
static EC_AffinePoint hash_to_curve_nu(const EC_Group &group, std::string_view hash_fn, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep)
bool is_identity() const
Return true if this point is the identity element.
static EC_AffinePoint identity(const EC_Group &group)
Return the identity element.
Definition ec_apoint.cpp:78
static std::optional< EC_AffinePoint > from_bigint_xy(const EC_Group &group, const BigInt &x, const BigInt &y)
Definition ec_apoint.cpp:92
static std::optional< EC_AffinePoint > mul_px_qy(const EC_AffinePoint &p, const EC_Scalar &x, const EC_AffinePoint &q, const EC_Scalar &y, RandomNumberGenerator &rng)
T serialize_uncompressed() const
Definition ec_apoint.h:194
EC_AffinePoint(const EC_Group &group, std::span< const uint8_t > bytes)
Definition ec_apoint.cpp:35
static EC_AffinePoint _from_inner(std::unique_ptr< EC_AffinePoint_Data > inner)
const std::shared_ptr< const EC_Group_Data > & _group() const
static std::optional< EC_AffinePoint > deserialize(const EC_Group &group, std::span< const uint8_t > bytes)
std::vector< uint8_t > serialize(EC_Point_Format format) const
Return an encoding depending on the requested format.
secure_vector< uint8_t > mul_x_only(const EC_Scalar &scalar, RandomNumberGenerator &rng, std::vector< BigInt > &ws) const
void serialize_x_to(std::span< uint8_t > bytes) const
T serialize_compressed() const
Definition ec_apoint.h:204
void serialize_compressed_to(std::span< uint8_t > bytes) const
const EC_AffinePoint_Data & _inner() const
Definition ec_apoint.h:237
void serialize_uncompressed_to(std::span< uint8_t > bytes) const
void serialize_y_to(std::span< uint8_t > bytes) const
EC_AffinePoint add(const EC_AffinePoint &q) const
EC_AffinePoint & operator=(const EC_AffinePoint &other)
Definition ec_apoint.cpp:23
bool operator==(const EC_AffinePoint &other) const
Definition ec_apoint.cpp:53
static EC_AffinePoint g_mul(const EC_Scalar &scalar, RandomNumberGenerator &rng, std::vector< BigInt > &ws)
static EC_AffinePoint generator(const EC_Group &group)
Return the standard group generator.
Definition ec_apoint.cpp:83
EC_AffinePoint mul(const EC_Scalar &scalar, RandomNumberGenerator &rng, std::vector< BigInt > &ws) const
const BigInt & get_g_y() const
Definition ec_group.cpp:570
const BigInt & get_p() const
Definition ec_group.cpp:514
const BigInt & get_g_x() const
Definition ec_group.cpp:566
const std::shared_ptr< EC_Group_Data > & _data() const
Definition ec_group.h:442
size_t get_p_bytes() const
Definition ec_group.cpp:502
virtual const std::shared_ptr< const EC_Group_Data > & group() const =0
const EC_Scalar_Data & _inner() const
Definition ec_scalar.h:222
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:788
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61