Botan 3.13.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#include <algorithm>
12
13namespace Botan {
14
15EC_Scalar EC_Scalar::_from_inner(std::unique_ptr<EC_Scalar_Data> inner) {
16 return EC_Scalar(std::move(inner));
17}
18
19EC_Scalar::EC_Scalar(std::unique_ptr<EC_Scalar_Data> scalar) : m_scalar(std::move(scalar)) {
20 BOTAN_ASSERT_NONNULL(m_scalar);
21}
22
23EC_Scalar::EC_Scalar(const EC_Scalar& other) : m_scalar(other.inner().clone()) {}
24
25EC_Scalar::EC_Scalar(EC_Scalar&& other) noexcept : m_scalar(std::move(other.m_scalar)) {}
26
28 if(this != &other) {
29 if(m_scalar == nullptr || m_scalar->group() != other.inner().group()) {
30 m_scalar = other.inner().clone();
31 } else {
32 this->assign(other);
33 }
34 }
35 return (*this);
36}
37
39 if(this != &other) {
40 // Even a cross-curve swap is accepted here
41 std::swap(m_scalar, other.m_scalar);
42 }
43 return (*this);
44}
45
46EC_Scalar::~EC_Scalar() = default;
47
48size_t EC_Scalar::bytes() const {
49 return m_scalar->bytes();
50}
51
52EC_Scalar EC_Scalar::from_bytes_with_trunc(const EC_Group& group, std::span<const uint8_t> bytes) {
53 return EC_Scalar(group._data()->scalar_from_bytes_with_trunc(bytes));
54}
55
56EC_Scalar EC_Scalar::from_bytes_mod_order(const EC_Group& group, std::span<const uint8_t> bytes) {
57 if(auto s = group._data()->scalar_from_bytes_mod_order(bytes)) {
58 return EC_Scalar(std::move(s));
59 } else {
60 throw Decoding_Error("EC_Scalar::from_bytes_mod_order input invalid");
61 }
62}
63
65 return EC_Scalar(group._data()->scalar_random(rng));
66}
67
69 return EC_Scalar(group._data()->scalar_one());
70}
71
73 if(auto data = group._data()->scalar_from_bigint(bn)) {
74 return EC_Scalar(std::move(data));
75 } else {
76 throw Invalid_Argument("EC_Scalar::from_bigint input out of range");
77 }
78}
79
81 secure_vector<uint8_t> bytes(m_scalar->bytes());
82 m_scalar->serialize_to(bytes);
84}
85
86//static
88 const auto& group = scalar._inner().group();
89 return EC_Scalar(group->gk_x_mod_order(scalar.inner(), rng));
90}
91
92void EC_Scalar::serialize_to(std::span<uint8_t> bytes) const {
93 inner().serialize_to(bytes);
94}
95
96void EC_Scalar::serialize_pair_to(std::span<uint8_t> bytes, const EC_Scalar& r, const EC_Scalar& s) {
97 BOTAN_ARG_CHECK(r._inner().group() == s._inner().group(), "Curve mismatch");
98 const size_t scalar_bytes = r.bytes();
99 BOTAN_ARG_CHECK(bytes.size() == 2 * scalar_bytes, "Invalid output length");
100 r.serialize_to(bytes.first(scalar_bytes));
101 s.serialize_to(bytes.last(scalar_bytes));
102}
103
104std::optional<std::pair<EC_Scalar, EC_Scalar>> EC_Scalar::deserialize_pair(const EC_Group& group,
105 std::span<const uint8_t> bytes) {
106 if(bytes.size() % 2 != 0) {
107 return {};
108 }
109
110 const size_t half = bytes.size() / 2;
111
112 auto r = EC_Scalar::deserialize(group, bytes.first(half));
113 auto s = EC_Scalar::deserialize(group, bytes.last(half));
114
115 if(r && s) {
116 return std::make_pair(r.value(), s.value());
117 } else {
118 return {};
119 }
120}
121
122std::optional<EC_Scalar> EC_Scalar::deserialize(const EC_Group& group, std::span<const uint8_t> bytes) {
123 if(auto v = group._data()->scalar_deserialize(bytes)) {
124 return EC_Scalar(std::move(v));
125 } else {
126 return {};
127 }
128}
129
130EC_Scalar::EC_Scalar(const EC_Group& group, std::span<const uint8_t> bytes) {
131 m_scalar = group._data()->scalar_deserialize(bytes);
132 if(!m_scalar) {
133 throw Decoding_Error("EC_Scalar::from_bytes is not a valid scalar value");
134 }
135}
136
137bool EC_Scalar::is_zero() const {
138 return inner().is_zero();
139}
140
142 return EC_Scalar(inner().invert());
143}
144
146 return EC_Scalar(inner().invert_vartime());
147}
148
150 return EC_Scalar(inner().negate());
151}
152
154 m_scalar->square_self();
155}
156
158 BOTAN_ARG_CHECK(inner().group() == x.inner().group(), "Curve mismatch");
159 return EC_Scalar(inner().add(x.inner()));
160}
161
163 BOTAN_ARG_CHECK(inner().group() == x.inner().group(), "Curve mismatch");
164 return EC_Scalar(inner().sub(x.inner()));
165}
166
168 BOTAN_ARG_CHECK(inner().group() == x.inner().group(), "Curve mismatch");
169 return EC_Scalar(inner().mul(x.inner()));
170}
171
173 if(this != &x) {
174 if(m_scalar == nullptr || m_scalar->group() != x.inner().group()) {
175 m_scalar = x.inner().clone();
176 } else {
177 m_scalar->assign(x.inner());
178 }
179 }
180}
181
183 m_scalar->zeroize();
184}
185
186bool EC_Scalar::is_eq(const EC_Scalar& x) const {
187 if(inner().group() != x.inner().group()) {
188 return false;
189 }
190
191 return inner().is_eq(x.inner());
192}
193
194//static
196 std::string_view hash_fn,
197 std::span<const uint8_t> input,
198 std::span<const uint8_t> domain_sep) {
199 /*
200 RFC 9380 Section 5.2
201 L = ceil((ceil(log2(p)) + k) / 8), where k is the security
202 parameter of the suite (e.g., k = 128)
203 */
204 const size_t scalar_bits = group.get_order_bits();
205 const size_t security_level = std::min<size_t>((scalar_bits + 1) / 2, 256);
206 secure_vector<uint8_t> uniform_bytes((scalar_bits + security_level + 7) / 8);
207
208 h2c_expand_message(hash_fn, scalar_bits, input, domain_sep)(uniform_bytes);
209
210 return EC_Scalar::from_bytes_mod_order(group, uniform_bytes);
211}
212
213} // namespace Botan
#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:83
const std::shared_ptr< EC_Group_Data > & _data() const
Definition ec_group.h:545
size_t get_order_bits() const
Definition ec_group.cpp:662
virtual const std::shared_ptr< const EC_Group_Data > & group() const =0
virtual std::unique_ptr< EC_Scalar_Data > clone() const =0
static EC_Scalar one(const EC_Group &group)
Definition ec_scalar.cpp:68
BigInt to_bigint() const
Definition ec_scalar.cpp:80
const EC_Scalar_Data & _inner() const
Definition ec_scalar.h:277
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:87
void serialize_to(std::span< uint8_t > bytes) const
Definition ec_scalar.cpp:92
bool is_zero() const
size_t bytes() const
Definition ec_scalar.cpp:48
static EC_Scalar from_bigint(const EC_Group &group, const BigInt &bn)
Definition ec_scalar.cpp:72
EC_Scalar & operator=(const EC_Scalar &other)
Definition ec_scalar.cpp:27
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:96
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:56
static EC_Scalar random(const EC_Group &group, RandomNumberGenerator &rng)
Definition ec_scalar.cpp:64
static EC_Scalar _from_inner(std::unique_ptr< EC_Scalar_Data > inner)
Definition ec_scalar.cpp:15
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:52
std::function< void(std::span< uint8_t >)> h2c_expand_message(std::string_view hash_fn, size_t order_bits, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep)
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128