Botan 3.9.0
Crypto and TLS for C&
ec_scalar.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_scalar.h>
8
9#include <botan/ec_group.h>
10#include <botan/internal/ec_inner_data.h>
11
12#if defined(BOTAN_HAS_XMD)
13 #include <botan/internal/xmd.h>
14#endif
15
16namespace Botan {
17
18EC_Scalar EC_Scalar::_from_inner(std::unique_ptr<EC_Scalar_Data> inner) {
19 return EC_Scalar(std::move(inner));
20}
21
22EC_Scalar::EC_Scalar(std::unique_ptr<EC_Scalar_Data> scalar) : m_scalar(std::move(scalar)) {
23 BOTAN_ASSERT_NONNULL(m_scalar);
24}
25
26EC_Scalar::EC_Scalar(const EC_Scalar& other) : m_scalar(other.inner().clone()) {}
27
28EC_Scalar::EC_Scalar(EC_Scalar&& other) noexcept : m_scalar(std::move(other.m_scalar)) {}
29
31 if(this != &other) {
32 this->assign(other);
33 }
34 return (*this);
35}
36
38 BOTAN_ARG_CHECK(_inner().group() == other._inner().group(), "Curve mismatch");
39 std::swap(m_scalar, other.m_scalar);
40 return (*this);
41}
42
43EC_Scalar::~EC_Scalar() = default;
44
45size_t EC_Scalar::bytes() const {
46 return m_scalar->bytes();
47}
48
49EC_Scalar EC_Scalar::from_bytes_with_trunc(const EC_Group& group, std::span<const uint8_t> bytes) {
50 return EC_Scalar(group._data()->scalar_from_bytes_with_trunc(bytes));
51}
52
53EC_Scalar EC_Scalar::from_bytes_mod_order(const EC_Group& group, std::span<const uint8_t> bytes) {
54 if(auto s = group._data()->scalar_from_bytes_mod_order(bytes)) {
55 return EC_Scalar(std::move(s));
56 } else {
57 throw Decoding_Error("EC_Scalar::from_bytes_mod_order input invalid");
58 }
59}
60
62 return EC_Scalar(group._data()->scalar_random(rng));
63}
64
66 return EC_Scalar(group._data()->scalar_one());
67}
68
70 if(auto data = group._data()->scalar_from_bigint(bn)) {
71 return EC_Scalar(std::move(data));
72 } else {
73 throw Invalid_Argument("EC_Scalar::from_bigint input out of range");
74 }
75}
76
78 secure_vector<uint8_t> bytes(m_scalar->bytes());
79 m_scalar->serialize_to(bytes);
81}
82
84 const auto& group = scalar._inner().group();
85 return EC_Scalar(group->gk_x_mod_order(scalar.inner(), rng));
86}
87
88void EC_Scalar::serialize_to(std::span<uint8_t> bytes) const {
89 inner().serialize_to(bytes);
90}
91
92void EC_Scalar::serialize_pair_to(std::span<uint8_t> bytes, const EC_Scalar& r, const EC_Scalar& s) {
93 BOTAN_ARG_CHECK(r._inner().group() == s._inner().group(), "Curve mismatch");
94 const size_t scalar_bytes = r.bytes();
95 BOTAN_ARG_CHECK(bytes.size() == 2 * scalar_bytes, "Invalid output length");
96 r.serialize_to(bytes.first(scalar_bytes));
97 s.serialize_to(bytes.last(scalar_bytes));
98}
99
100std::optional<std::pair<EC_Scalar, EC_Scalar>> EC_Scalar::deserialize_pair(const EC_Group& group,
101 std::span<const uint8_t> bytes) {
102 if(bytes.size() % 2 != 0) {
103 return {};
104 }
105
106 const size_t half = bytes.size() / 2;
107
108 auto r = EC_Scalar::deserialize(group, bytes.first(half));
109 auto s = EC_Scalar::deserialize(group, bytes.last(half));
110
111 if(r && s) {
112 return std::make_pair(r.value(), s.value());
113 } else {
114 return {};
115 }
116}
117
118std::optional<EC_Scalar> EC_Scalar::deserialize(const EC_Group& group, std::span<const uint8_t> bytes) {
119 if(auto v = group._data()->scalar_deserialize(bytes)) {
120 return EC_Scalar(std::move(v));
121 } else {
122 return {};
123 }
124}
125
126EC_Scalar::EC_Scalar(const EC_Group& group, std::span<const uint8_t> bytes) {
127 m_scalar = group._data()->scalar_deserialize(bytes);
128 if(!m_scalar) {
129 throw Decoding_Error("EC_Scalar::from_bytes is not a valid scalar value");
130 }
131}
132
133bool EC_Scalar::is_zero() const {
134 return inner().is_zero();
135}
136
138 return EC_Scalar(inner().invert());
139}
140
142 return EC_Scalar(inner().invert_vartime());
143}
144
146 return EC_Scalar(inner().negate());
147}
148
150 m_scalar->square_self();
151}
152
154 return EC_Scalar(inner().add(x.inner()));
155}
156
158 return EC_Scalar(inner().sub(x.inner()));
159}
160
162 return EC_Scalar(inner().mul(x.inner()));
163}
164
166 m_scalar->assign(x.inner());
167}
168
170 m_scalar->zeroize();
171}
172
173bool EC_Scalar::is_eq(const EC_Scalar& x) const {
174 return inner().is_eq(x.inner());
175}
176
177//static
179 std::string_view hash_fn,
180 std::span<const uint8_t> input,
181 std::span<const uint8_t> domain_sep) {
182#if defined(BOTAN_HAS_XMD)
183
184 /*
185 * This could be extended to support expand_message_xof or a MHF like Argon2
186 */
187 if(hash_fn.starts_with("SHAKE")) {
188 throw Not_Implemented("Hash to scalar currently does not support expand_message_xof");
189 }
190
191 const size_t scalar_bits = group.get_order_bits();
192 const size_t security_level = (scalar_bits + 1) / 2;
193 secure_vector<uint8_t> uniform_bytes((scalar_bits + security_level + 7) / 8);
194 expand_message_xmd(hash_fn, uniform_bytes, input, domain_sep);
195
196 return EC_Scalar::from_bytes_mod_order(group, uniform_bytes);
197#else
198 BOTAN_UNUSED(group, hash_fn, input, domain_sep);
199 throw Not_Implemented("EC_Scalar::hash not available due to missing XMD");
200#endif
201}
202
203} // namespace Botan
#define BOTAN_UNUSED
Definition assert.h:144
#define BOTAN_ASSERT_NONNULL(ptr)
Definition assert.h:114
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
static BigInt from_bytes(std::span< const uint8_t > bytes)
Definition bigint.cpp:87
const std::shared_ptr< EC_Group_Data > & _data() const
Definition ec_group.h:462
size_t get_order_bits() const
Definition ec_group.cpp:542
virtual const std::shared_ptr< const EC_Group_Data > & group() const =0
static EC_Scalar one(const EC_Group &group)
Definition ec_scalar.cpp:65
BigInt to_bigint() const
Definition ec_scalar.cpp:77
const EC_Scalar_Data & _inner() const
Definition ec_scalar.h:244
static EC_Scalar hash(const EC_Group &group, std::string_view hash_fn, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep)
void assign(const EC_Scalar &x)
bool is_eq(const EC_Scalar &x) const
static std::optional< EC_Scalar > deserialize(const EC_Group &group, std::span< const uint8_t > bytes)
EC_Scalar mul(const EC_Scalar &x) const
EC_Scalar add(const EC_Scalar &x) const
static EC_Scalar gk_x_mod_order(const EC_Scalar &scalar, RandomNumberGenerator &rng)
Definition ec_scalar.cpp:83
void serialize_to(std::span< uint8_t > bytes) const
Definition ec_scalar.cpp:88
bool is_zero() const
size_t bytes() const
Definition ec_scalar.cpp:45
static EC_Scalar from_bigint(const EC_Group &group, const BigInt &bn)
Definition ec_scalar.cpp:69
EC_Scalar & operator=(const EC_Scalar &other)
Definition ec_scalar.cpp:30
EC_Scalar invert_vartime() const
EC_Scalar invert() const
static void serialize_pair_to(std::span< uint8_t > bytes, const EC_Scalar &r, const EC_Scalar &s)
Definition ec_scalar.cpp:92
EC_Scalar(const EC_Group &group, std::span< const uint8_t > bytes)
static EC_Scalar from_bytes_mod_order(const EC_Group &group, std::span< const uint8_t > bytes)
Definition ec_scalar.cpp:53
static EC_Scalar random(const EC_Group &group, RandomNumberGenerator &rng)
Definition ec_scalar.cpp:61
static EC_Scalar _from_inner(std::unique_ptr< EC_Scalar_Data > inner)
Definition ec_scalar.cpp:18
EC_Scalar negate() const
EC_Scalar sub(const EC_Scalar &x) const
static std::optional< std::pair< EC_Scalar, EC_Scalar > > deserialize_pair(const EC_Group &group, std::span< const uint8_t > bytes)
static EC_Scalar from_bytes_with_trunc(const EC_Group &group, std::span< const uint8_t > bytes)
Definition ec_scalar.cpp:49
void expand_message_xmd(std::string_view hash_fn, std::span< uint8_t > output, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep)
Definition xmd.cpp:17
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:69