Botan 3.13.0
Crypto and TLS for C&
ec_inner_bn.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_bn.h>
8
9#include <botan/mem_ops.h>
10#include <botan/internal/buffer_stuffer.h>
11#include <botan/internal/mod_inv.h>
12
13namespace Botan {
14
16 const auto* p = dynamic_cast<const EC_Scalar_Data_BN*>(&data);
17 if(p == nullptr) {
18 throw Invalid_State("Failed conversion to EC_Scalar_Data_BN");
19 }
20 return *p;
21}
22
23const std::shared_ptr<const EC_Group_Data>& EC_Scalar_Data_BN::group() const {
24 return m_group;
25}
26
28 return this->group()->order_bytes();
29}
30
31std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_BN::clone() const {
32 return std::make_unique<EC_Scalar_Data_BN>(this->group(), this->value());
33}
34
36 return this->value().is_zero();
37}
38
39bool EC_Scalar_Data_BN::is_eq(const EC_Scalar_Data& other) const {
40 return (value() == checked_ref(other).value());
41}
42
44 BOTAN_STATE_CHECK(other.group() == this->group());
45 m_v = checked_ref(other).value();
46}
47
49 // BigInt stores its value in a secure_vector, after swapping the existing
50 // value will go out of scope (inside `zero`) and be wiped properly.
51 BigInt zero;
52 std::swap(m_v, zero);
53}
54
56 m_v = m_group->mod_order().square(m_v);
57}
58
59std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_BN::negate() const {
60 return std::make_unique<EC_Scalar_Data_BN>(m_group, m_group->mod_order().reduce(m_group->order() - m_v));
61}
62
63std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_BN::invert() const {
64 if(m_v.is_zero()) {
65 return std::make_unique<EC_Scalar_Data_BN>(m_group, m_v);
66 } else {
67 return std::make_unique<EC_Scalar_Data_BN>(m_group, inverse_mod_public_prime(m_v, m_group->order()));
68 }
69}
70
71std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_BN::invert_vartime() const {
72 if(m_v.is_zero()) {
73 return std::make_unique<EC_Scalar_Data_BN>(m_group, m_v);
74 } else {
75 return std::make_unique<EC_Scalar_Data_BN>(m_group, inverse_mod_public_prime(m_v, m_group->order()));
76 }
77}
78
79std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_BN::add(const EC_Scalar_Data& other) const {
80 return std::make_unique<EC_Scalar_Data_BN>(m_group, m_group->mod_order().reduce(m_v + checked_ref(other).value()));
81}
82
83std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_BN::sub(const EC_Scalar_Data& other) const {
84 return std::make_unique<EC_Scalar_Data_BN>(
85 m_group, m_group->mod_order().reduce(m_v + (m_group->order() - checked_ref(other).value())));
86}
87
88std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_BN::mul(const EC_Scalar_Data& other) const {
89 return std::make_unique<EC_Scalar_Data_BN>(m_group, m_group->mod_order().multiply(m_v, checked_ref(other).value()));
90}
91
92void EC_Scalar_Data_BN::serialize_to(std::span<uint8_t> bytes) const {
93 BOTAN_ARG_CHECK(bytes.size() == m_group->order_bytes(), "Invalid output length");
94 m_v.serialize_to(bytes);
95}
96
97EC_AffinePoint_Data_BN::EC_AffinePoint_Data_BN(std::shared_ptr<const EC_Group_Data> group, EC_Point pt) :
98 m_group(std::move(group)), m_pt(std::move(pt)) {
99 if(!m_pt.is_zero()) {
100 m_pt.force_affine();
101 m_xy = m_pt.xy_bytes();
102 }
103}
104
105std::unique_ptr<EC_AffinePoint_Data> EC_AffinePoint_Data_BN::clone() const {
106 return std::make_unique<EC_AffinePoint_Data_BN>(m_group, m_pt);
107}
108
109const std::shared_ptr<const EC_Group_Data>& EC_AffinePoint_Data_BN::group() const {
110 return m_group;
111}
112
113std::unique_ptr<EC_AffinePoint_Data> EC_AffinePoint_Data_BN::mul(const EC_Scalar_Data& scalar,
114 RandomNumberGenerator& rng) const {
115 BOTAN_ARG_CHECK(scalar.group() == m_group, "Curve mismatch");
116 const auto& bn = EC_Scalar_Data_BN::checked_ref(scalar);
117
118 std::vector<BigInt> ws;
119 const EC_Point_Var_Point_Precompute mul(m_pt, rng, ws);
120
121 // We pass order*cofactor here to "correctly" handle the case where the
122 // point is on the curve but not in the prime order subgroup. This only
123 // matters for groups with cofactor > 1
124 // See https://github.com/randombit/botan/issues/3800
125
126 const auto order = m_group->order() * m_group->cofactor();
127 auto pt = mul.mul(bn.value(), rng, order, ws);
128 return std::make_unique<EC_AffinePoint_Data_BN>(m_group, std::move(pt));
129}
130
132 RandomNumberGenerator& rng) const {
133 BOTAN_ARG_CHECK(scalar.group() == m_group, "Curve mismatch");
134 const auto& bn = EC_Scalar_Data_BN::checked_ref(scalar);
135
136 std::vector<BigInt> ws;
137 const EC_Point_Var_Point_Precompute mul(m_pt, rng, ws);
138
139 // We pass order*cofactor here to "correctly" handle the case where the
140 // point is on the curve but not in the prime order subgroup. This only
141 // matters for groups with cofactor > 1
142 // See https://github.com/randombit/botan/issues/3800
143
144 const auto order = m_group->order() * m_group->cofactor();
145 auto pt = mul.mul(bn.value(), rng, order, ws);
146 return pt.x_bytes();
147}
148
150 return m_group->p_bytes();
151}
152
154 return m_xy.empty();
155}
156
157void EC_AffinePoint_Data_BN::serialize_x_to(std::span<uint8_t> bytes) const {
159 const size_t fe_bytes = this->field_element_bytes();
160 BOTAN_ARG_CHECK(bytes.size() == fe_bytes, "Invalid output size");
161 copy_mem(bytes, std::span{m_xy}.first(fe_bytes));
162}
163
164void EC_AffinePoint_Data_BN::serialize_y_to(std::span<uint8_t> bytes) const {
166 const size_t fe_bytes = this->field_element_bytes();
167 BOTAN_ARG_CHECK(bytes.size() == fe_bytes, "Invalid output size");
168 copy_mem(bytes, std::span{m_xy}.last(fe_bytes));
169}
170
171void EC_AffinePoint_Data_BN::serialize_xy_to(std::span<uint8_t> bytes) const {
173 const size_t fe_bytes = this->field_element_bytes();
174 BOTAN_ARG_CHECK(bytes.size() == 2 * fe_bytes, "Invalid output size");
175 copy_mem(bytes, m_xy);
176}
177
178void EC_AffinePoint_Data_BN::serialize_compressed_to(std::span<uint8_t> bytes) const {
180 const size_t fe_bytes = this->field_element_bytes();
181 BOTAN_ARG_CHECK(bytes.size() == 1 + fe_bytes, "Invalid output size");
182 const bool y_is_odd = (m_xy[m_xy.size() - 1] & 0x01) == 0x01;
183
184 BufferStuffer stuffer(bytes);
185 stuffer.append(y_is_odd ? 0x03 : 0x02);
186 serialize_x_to(stuffer.next(fe_bytes));
187}
188
189void EC_AffinePoint_Data_BN::serialize_uncompressed_to(std::span<uint8_t> bytes) const {
191 const size_t fe_bytes = this->field_element_bytes();
192 BOTAN_ARG_CHECK(bytes.size() == 1 + 2 * fe_bytes, "Invalid output size");
193 BufferStuffer stuffer(bytes);
194 stuffer.append(0x04);
195 stuffer.append(m_xy);
196}
197
199 m_group(g.group()), m_tbl(g.to_legacy_point(), h.to_legacy_point()) {
200 BOTAN_ARG_CHECK(h.group() == m_group, "Curve mismatch");
201}
202
203std::unique_ptr<EC_AffinePoint_Data> EC_Mul2Table_Data_BN::mul2_vartime(const EC_Scalar_Data& x,
204 const EC_Scalar_Data& y) const {
205 BOTAN_ARG_CHECK(x.group() == m_group && y.group() == m_group, "Curve mismatch");
206
207 const auto& bn_x = EC_Scalar_Data_BN::checked_ref(x);
208 const auto& bn_y = EC_Scalar_Data_BN::checked_ref(y);
209 auto pt = m_tbl.multi_exp(bn_x.value(), bn_y.value());
210
211 if(pt.is_zero()) {
212 return nullptr;
213 }
214 return std::make_unique<EC_AffinePoint_Data_BN>(m_group, std::move(pt));
215}
216
218 const EC_Scalar_Data& x,
219 const EC_Scalar_Data& y) const {
220 BOTAN_ARG_CHECK(x.group() == m_group && y.group() == m_group && v.group() == m_group, "Curve mismatch");
221
222 const auto& bn_v = EC_Scalar_Data_BN::checked_ref(v);
223 const auto& bn_x = EC_Scalar_Data_BN::checked_ref(x);
224 const auto& bn_y = EC_Scalar_Data_BN::checked_ref(y);
225 const auto pt = m_tbl.multi_exp(bn_x.value(), bn_y.value());
226
227 return pt._is_x_eq_to_v_mod_order(bn_v.value());
228}
229
230} // namespace Botan
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
bool is_zero() const
Definition bigint.h:510
Helper class to ease in-place marshalling of concatenated fixed-length values.
constexpr void append(std::span< const uint8_t > buffer)
constexpr std::span< uint8_t > next(size_t bytes)
void serialize_x_to(std::span< uint8_t > bytes) const override
const std::shared_ptr< const EC_Group_Data > & group() const override
secure_vector< uint8_t > mul_x_only(const EC_Scalar_Data &scalar, RandomNumberGenerator &rng) const override
EC_AffinePoint_Data_BN(std::shared_ptr< const EC_Group_Data > group, EC_Point pt)
void serialize_compressed_to(std::span< uint8_t > bytes) const override
std::unique_ptr< EC_AffinePoint_Data > mul(const EC_Scalar_Data &scalar, RandomNumberGenerator &rng) const override
std::unique_ptr< EC_AffinePoint_Data > clone() const override
size_t field_element_bytes() const override
bool is_identity() const override
void serialize_y_to(std::span< uint8_t > bytes) const override
void serialize_xy_to(std::span< uint8_t > bytes) const override
void serialize_uncompressed_to(std::span< uint8_t > bytes) const override
virtual const std::shared_ptr< const EC_Group_Data > & group() const =0
EC_Mul2Table_Data_BN(const EC_AffinePoint_Data &g, const EC_AffinePoint_Data &h)
bool mul2_vartime_x_mod_order_eq(const EC_Scalar_Data &v, const EC_Scalar_Data &x, const EC_Scalar_Data &y) const override
std::unique_ptr< EC_AffinePoint_Data > mul2_vartime(const EC_Scalar_Data &x, const EC_Scalar_Data &y) const override
std::unique_ptr< EC_Scalar_Data > invert() const override
std::unique_ptr< EC_Scalar_Data > clone() const override
std::unique_ptr< EC_Scalar_Data > negate() const override
const std::shared_ptr< const EC_Group_Data > & group() const override
bool is_zero() const override
std::unique_ptr< EC_Scalar_Data > sub(const EC_Scalar_Data &other) const override
void square_self() override
std::unique_ptr< EC_Scalar_Data > add(const EC_Scalar_Data &other) const override
std::unique_ptr< EC_Scalar_Data > mul(const EC_Scalar_Data &other) const override
const BigInt & value() const
Definition ec_inner_bn.h:52
void serialize_to(std::span< uint8_t > bytes) const override
static const EC_Scalar_Data_BN & checked_ref(const EC_Scalar_Data &data)
EC_Scalar_Data_BN(std::shared_ptr< const EC_Group_Data > group, BigInt v)
Definition ec_inner_bn.h:17
bool is_eq(const EC_Scalar_Data &y) const override
void zeroize() override
std::unique_ptr< EC_Scalar_Data > invert_vartime() const override
void assign(const EC_Scalar_Data &y) override
size_t bytes() const override
virtual const std::shared_ptr< const EC_Group_Data > & group() const =0
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144
BigInt inverse_mod_public_prime(const BigInt &x, const BigInt &p)
Definition mod_inv.cpp:294
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128