Coverage Report

Created: 2024-11-29 06:10

/src/botan/src/lib/pubkey/ec_group/ec_inner_bn.cpp
Line
Count
Source (jump to first uncovered line)
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
namespace Botan {
10
11
1.85k
const EC_Scalar_Data_BN& EC_Scalar_Data_BN::checked_ref(const EC_Scalar_Data& data) {
12
1.85k
   const auto* p = dynamic_cast<const EC_Scalar_Data_BN*>(&data);
13
1.85k
   if(!p) {
14
0
      throw Invalid_State("Failed conversion to EC_Scalar_Data_BN");
15
0
   }
16
1.85k
   return *p;
17
1.85k
}
18
19
2.17k
const std::shared_ptr<const EC_Group_Data>& EC_Scalar_Data_BN::group() const {
20
2.17k
   return m_group;
21
2.17k
}
22
23
221
size_t EC_Scalar_Data_BN::bytes() const {
24
221
   return this->group()->order_bytes();
25
221
}
26
27
704
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_BN::clone() const {
28
704
   return std::make_unique<EC_Scalar_Data_BN>(this->group(), this->value());
29
704
}
30
31
904
bool EC_Scalar_Data_BN::is_zero() const {
32
904
   return this->value().is_zero();
33
904
}
34
35
0
bool EC_Scalar_Data_BN::is_eq(const EC_Scalar_Data& other) const {
36
0
   return (value() == checked_ref(other).value());
37
0
}
38
39
0
void EC_Scalar_Data_BN::assign(const EC_Scalar_Data& other) {
40
0
   m_v = checked_ref(other).value();
41
0
}
42
43
0
void EC_Scalar_Data_BN::square_self() {
44
0
   m_group->square_mod_order(m_v);
45
0
}
46
47
200
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_BN::negate() const {
48
200
   return std::make_unique<EC_Scalar_Data_BN>(m_group, m_group->mod_order(-m_v));
49
200
}
50
51
351
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_BN::invert() const {
52
351
   return std::make_unique<EC_Scalar_Data_BN>(m_group, m_group->inverse_mod_order(m_v));
53
351
}
54
55
0
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_BN::add(const EC_Scalar_Data& other) const {
56
0
   return std::make_unique<EC_Scalar_Data_BN>(m_group, m_group->mod_order(m_v + checked_ref(other).value()));
57
0
}
58
59
0
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_BN::sub(const EC_Scalar_Data& other) const {
60
0
   return std::make_unique<EC_Scalar_Data_BN>(m_group, m_group->mod_order(m_v - checked_ref(other).value()));
61
0
}
62
63
702
std::unique_ptr<EC_Scalar_Data> EC_Scalar_Data_BN::mul(const EC_Scalar_Data& other) const {
64
702
   return std::make_unique<EC_Scalar_Data_BN>(m_group, m_group->multiply_mod_order(m_v, checked_ref(other).value()));
65
702
}
66
67
221
void EC_Scalar_Data_BN::serialize_to(std::span<uint8_t> bytes) const {
68
221
   BOTAN_ARG_CHECK(bytes.size() == m_group->order_bytes(), "Invalid output length");
69
221
   m_v.serialize_to(bytes);
70
221
}
71
72
EC_AffinePoint_Data_BN::EC_AffinePoint_Data_BN(std::shared_ptr<const EC_Group_Data> group, EC_Point pt) :
73
541
      m_group(std::move(group)), m_pt(std::move(pt)) {
74
541
   if(!m_pt.is_zero()) {
75
541
      m_pt.force_affine();
76
541
      m_xy = m_pt.xy_bytes();
77
541
   }
78
541
}
79
80
EC_AffinePoint_Data_BN::EC_AffinePoint_Data_BN(std::shared_ptr<const EC_Group_Data> group,
81
                                               std::span<const uint8_t> pt) :
82
912
      m_group(std::move(group)) {
83
912
   BOTAN_ASSERT_NONNULL(m_group);
84
912
   m_pt = Botan::OS2ECP(pt, m_group->curve());
85
912
   if(!m_pt.is_zero()) {
86
300
      m_xy = m_pt.xy_bytes();
87
300
   }
88
912
}
89
90
0
std::unique_ptr<EC_AffinePoint_Data> EC_AffinePoint_Data_BN::clone() const {
91
0
   return std::make_unique<EC_AffinePoint_Data_BN>(m_group, m_pt);
92
0
}
93
94
1.32k
const std::shared_ptr<const EC_Group_Data>& EC_AffinePoint_Data_BN::group() const {
95
1.32k
   return m_group;
96
1.32k
}
97
98
std::unique_ptr<EC_AffinePoint_Data> EC_AffinePoint_Data_BN::mul(const EC_Scalar_Data& scalar,
99
                                                                 RandomNumberGenerator& rng,
100
0
                                                                 std::vector<BigInt>& ws) const {
101
0
   BOTAN_ARG_CHECK(scalar.group() == m_group, "Curve mismatch");
102
0
   const auto& bn = EC_Scalar_Data_BN::checked_ref(scalar);
103
104
0
   EC_Point_Var_Point_Precompute mul(m_pt, rng, ws);
105
106
   // We pass order*cofactor here to "correctly" handle the case where the
107
   // point is on the curve but not in the prime order subgroup. This only
108
   // matters for groups with cofactor > 1
109
   // See https://github.com/randombit/botan/issues/3800
110
111
0
   const auto order = m_group->order() * m_group->cofactor();
112
0
   auto pt = mul.mul(bn.value(), rng, order, ws);
113
0
   return std::make_unique<EC_AffinePoint_Data_BN>(m_group, std::move(pt));
114
0
}
115
116
0
size_t EC_AffinePoint_Data_BN::field_element_bytes() const {
117
0
   return m_group->p_bytes();
118
0
}
119
120
0
bool EC_AffinePoint_Data_BN::is_identity() const {
121
0
   return m_xy.empty();
122
0
}
123
124
0
void EC_AffinePoint_Data_BN::serialize_x_to(std::span<uint8_t> bytes) const {
125
0
   BOTAN_STATE_CHECK(!this->is_identity());
126
0
   const size_t fe_bytes = this->field_element_bytes();
127
0
   BOTAN_ARG_CHECK(bytes.size() == fe_bytes, "Invalid output size");
128
0
   copy_mem(bytes, std::span{m_xy}.first(fe_bytes));
129
0
}
130
131
0
void EC_AffinePoint_Data_BN::serialize_y_to(std::span<uint8_t> bytes) const {
132
0
   BOTAN_STATE_CHECK(!this->is_identity());
133
0
   const size_t fe_bytes = this->field_element_bytes();
134
0
   BOTAN_ARG_CHECK(bytes.size() == fe_bytes, "Invalid output size");
135
0
   copy_mem(bytes, std::span{m_xy}.last(fe_bytes));
136
0
}
137
138
0
void EC_AffinePoint_Data_BN::serialize_xy_to(std::span<uint8_t> bytes) const {
139
0
   BOTAN_STATE_CHECK(!this->is_identity());
140
0
   const size_t fe_bytes = this->field_element_bytes();
141
0
   BOTAN_ARG_CHECK(bytes.size() == 2 * fe_bytes, "Invalid output size");
142
0
   copy_mem(bytes, m_xy);
143
0
}
144
145
0
void EC_AffinePoint_Data_BN::serialize_compressed_to(std::span<uint8_t> bytes) const {
146
0
   BOTAN_STATE_CHECK(!this->is_identity());
147
0
   const size_t fe_bytes = this->field_element_bytes();
148
0
   BOTAN_ARG_CHECK(bytes.size() == 1 + fe_bytes, "Invalid output size");
149
0
   const bool y_is_odd = (m_xy[m_xy.size() - 1] & 0x01) == 0x01;
150
151
0
   BufferStuffer stuffer(bytes);
152
0
   stuffer.append(y_is_odd ? 0x03 : 0x02);
153
0
   serialize_x_to(stuffer.next(fe_bytes));
154
0
}
155
156
0
void EC_AffinePoint_Data_BN::serialize_uncompressed_to(std::span<uint8_t> bytes) const {
157
0
   BOTAN_STATE_CHECK(!this->is_identity());
158
0
   const size_t fe_bytes = this->field_element_bytes();
159
0
   BOTAN_ARG_CHECK(bytes.size() == 1 + 2 * fe_bytes, "Invalid output size");
160
0
   BufferStuffer stuffer(bytes);
161
0
   stuffer.append(0x04);
162
0
   stuffer.append(m_xy);
163
0
}
164
165
EC_Mul2Table_Data_BN::EC_Mul2Table_Data_BN(const EC_AffinePoint_Data& g, const EC_AffinePoint_Data& h) :
166
443
      m_group(g.group()), m_tbl(g.to_legacy_point(), h.to_legacy_point()) {
167
443
   BOTAN_ARG_CHECK(h.group() == m_group, "Curve mismatch");
168
443
}
169
170
std::unique_ptr<EC_AffinePoint_Data> EC_Mul2Table_Data_BN::mul2_vartime(const EC_Scalar_Data& x,
171
0
                                                                        const EC_Scalar_Data& y) const {
172
0
   BOTAN_ARG_CHECK(x.group() == m_group && y.group() == m_group, "Curve mismatch");
173
174
0
   const auto& bn_x = EC_Scalar_Data_BN::checked_ref(x);
175
0
   const auto& bn_y = EC_Scalar_Data_BN::checked_ref(y);
176
0
   auto pt = m_tbl.multi_exp(bn_x.value(), bn_y.value());
177
178
0
   if(pt.is_zero()) {
179
0
      return nullptr;
180
0
   }
181
0
   return std::make_unique<EC_AffinePoint_Data_BN>(m_group, std::move(pt));
182
0
}
183
184
bool EC_Mul2Table_Data_BN::mul2_vartime_x_mod_order_eq(const EC_Scalar_Data& v,
185
                                                       const EC_Scalar_Data& x,
186
351
                                                       const EC_Scalar_Data& y) const {
187
351
   BOTAN_ARG_CHECK(x.group() == m_group && y.group() == m_group && v.group() == m_group, "Curve mismatch");
188
189
351
   const auto& bn_v = EC_Scalar_Data_BN::checked_ref(v);
190
351
   const auto& bn_x = EC_Scalar_Data_BN::checked_ref(x);
191
351
   const auto& bn_y = EC_Scalar_Data_BN::checked_ref(y);
192
351
   const auto pt = m_tbl.multi_exp(bn_x.value(), bn_y.value());
193
194
351
   return pt._is_x_eq_to_v_mod_order(bn_v.value());
195
351
}
196
197
}  // namespace Botan