Botan 3.5.0
Crypto and TLS for C&
pcurves_wrap.h
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#ifndef BOTAN_PCURVES_WRAP_H_
8#define BOTAN_PCURVES_WRAP_H_
9
10#include <botan/internal/pcurves.h>
11#include <botan/internal/pcurves_impl.h>
12
13namespace Botan::PCurve {
14
15template <typename C>
17 public:
19 public:
20 static constexpr size_t WindowBits = 4;
21
22 const WindowedMul2Table<C, WindowBits>& table() const { return m_table; }
23
24 explicit PrecomputedMul2TableC(const typename C::AffinePoint& x, const typename C::AffinePoint& y) :
25 m_table(x, y) {}
26
27 private:
29 };
30
31 static_assert(C::OrderBits <= PrimeOrderCurve::MaximumBitLength);
32 static_assert(C::PrimeFieldBits <= PrimeOrderCurve::MaximumBitLength);
33
34 size_t order_bits() const override { return C::OrderBits; }
35
36 size_t scalar_bytes() const override { return C::Scalar::BYTES; }
37
38 size_t field_element_bytes() const override { return C::FieldElement::BYTES; }
39
40 ProjectivePoint mul_by_g(const Scalar& scalar, RandomNumberGenerator& rng) const override {
41 return stash(m_mul_by_g.mul(from_stash(scalar), rng));
42 }
43
44 ProjectivePoint mul(const AffinePoint& pt, const Scalar& scalar, RandomNumberGenerator& rng) const override {
45 auto tbl = WindowedMulTable<C, 4>(from_stash(pt));
46 return stash(tbl.mul(from_stash(scalar), rng));
47 }
48
49 std::unique_ptr<const PrecomputedMul2Table> mul2_setup(const AffinePoint& x,
50 const AffinePoint& y) const override {
51 return std::make_unique<PrecomputedMul2TableC>(from_stash(x), from_stash(y));
52 }
53
54 std::optional<ProjectivePoint> mul2_vartime(const PrecomputedMul2Table& tableb,
55 const Scalar& s1,
56 const Scalar& s2) const override {
57 try {
58 const auto& table = dynamic_cast<const PrecomputedMul2TableC&>(tableb);
59 auto pt = table.table().mul2_vartime(from_stash(s1), from_stash(s2));
60 if(pt.is_identity().as_bool()) {
61 return {};
62 } else {
63 return stash(pt);
64 }
65 } catch(std::bad_cast&) {
66 throw Invalid_Argument("Curve mismatch");
67 }
68 }
69
70 std::optional<Scalar> mul2_vartime_x_mod_order(const PrecomputedMul2Table& tableb,
71 const Scalar& s1,
72 const Scalar& s2) const override {
73 try {
74 const auto& table = dynamic_cast<const PrecomputedMul2TableC&>(tableb);
75 const auto pt = table.table().mul2_vartime(from_stash(s1), from_stash(s2));
76 // Variable time here, so the early return is fine
77 if(pt.is_identity().as_bool()) {
78 return {};
79 }
80 std::array<uint8_t, C::FieldElement::BYTES> x_bytes;
81 pt.to_affine().x().serialize_to(std::span{x_bytes});
82 return stash(C::Scalar::from_wide_bytes(std::span<const uint8_t, C::FieldElement::BYTES>{x_bytes}));
83 } catch(std::bad_cast&) {
84 throw Invalid_Argument("Curve mismatch");
85 }
86 }
87
88 Scalar base_point_mul_x_mod_order(const Scalar& scalar, RandomNumberGenerator& rng) const override {
89 auto pt = m_mul_by_g.mul(from_stash(scalar), rng);
90 std::array<uint8_t, C::FieldElement::BYTES> x_bytes;
91 pt.to_affine().x().serialize_to(std::span{x_bytes});
92 return stash(C::Scalar::from_wide_bytes(std::span<const uint8_t, C::FieldElement::BYTES>{x_bytes}));
93 }
94
95 AffinePoint generator() const override { return stash(C::G); }
96
97 AffinePoint point_to_affine(const ProjectivePoint& pt) const override {
98 return stash(from_stash(pt).to_affine());
99 }
100
102 return stash(C::ProjectivePoint::from_affine(from_stash(pt)));
103 }
104
105 ProjectivePoint point_double(const ProjectivePoint& pt) const override { return stash(from_stash(pt).dbl()); }
106
107 ProjectivePoint point_add(const ProjectivePoint& a, const ProjectivePoint& b) const override {
108 return stash(from_stash(a) + from_stash(b));
109 }
110
111 ProjectivePoint point_add_mixed(const ProjectivePoint& a, const AffinePoint& b) const override {
112 return stash(from_stash(a) + from_stash(b));
113 }
114
115 ProjectivePoint point_negate(const ProjectivePoint& pt) const override { return stash(from_stash(pt).negate()); }
116
117 bool affine_point_is_identity(const AffinePoint& pt) const override {
118 return from_stash(pt).is_identity().as_bool();
119 }
120
121 void serialize_point(std::span<uint8_t> bytes, const AffinePoint& pt) const override {
122 BOTAN_ARG_CHECK(bytes.size() == C::AffinePoint::BYTES, "Invalid length for serialize_point");
123 from_stash(pt).serialize_to(bytes.subspan<0, C::AffinePoint::BYTES>());
124 }
125
126 void serialize_point_compressed(std::span<uint8_t> bytes, const AffinePoint& pt) const override {
127 BOTAN_ARG_CHECK(bytes.size() == C::AffinePoint::COMPRESSED_BYTES,
128 "Invalid length for serialize_point_compressed");
129 from_stash(pt).serialize_compressed_to(bytes.subspan<0, C::AffinePoint::COMPRESSED_BYTES>());
130 }
131
132 void serialize_point_x(std::span<uint8_t> bytes, const AffinePoint& pt) const override {
133 BOTAN_ARG_CHECK(bytes.size() == C::FieldElement::BYTES, "Invalid length for serialize_point_x");
134 from_stash(pt).x().serialize_to(bytes.subspan<0, C::FieldElement::BYTES>());
135 }
136
137 void serialize_scalar(std::span<uint8_t> bytes, const Scalar& scalar) const override {
138 BOTAN_ARG_CHECK(bytes.size() == C::Scalar::BYTES, "Invalid length to serialize_scalar");
139 return from_stash(scalar).serialize_to(bytes.subspan<0, C::Scalar::BYTES>());
140 }
141
142 std::optional<Scalar> deserialize_scalar(std::span<const uint8_t> bytes) const override {
143 if(auto scalar = C::Scalar::deserialize(bytes)) {
144 if(!scalar->is_zero().as_bool()) {
145 return stash(*scalar);
146 }
147 }
148
149 return {};
150 }
151
152 Scalar scalar_from_bits_with_trunc(std::span<const uint8_t> bytes) const override {
153 return stash(C::Scalar::from_bits_with_trunc(bytes));
154 }
155
156 std::optional<Scalar> scalar_from_wide_bytes(std::span<const uint8_t> bytes) const override {
157 if(auto s = C::Scalar::from_wide_bytes_varlen(bytes)) {
158 return stash(*s);
159 } else {
160 return {};
161 }
162 }
163
164 std::optional<AffinePoint> deserialize_point(std::span<const uint8_t> bytes) const override {
165 if(auto pt = C::AffinePoint::deserialize(bytes)) {
166 return stash(*pt);
167 } else {
168 return {};
169 }
170 }
171
172 ProjectivePoint hash_to_curve(std::string_view hash,
173 std::span<const uint8_t> input,
174 std::span<const uint8_t> domain_sep,
175 bool random_oracle) const override {
176 if constexpr(C::ValidForSswuHash) {
177 return stash(hash_to_curve_sswu<C>(hash, random_oracle, input, domain_sep));
178 } else {
179 throw Not_Implemented("Hash to curve is not implemented for this curve");
180 }
181 }
182
183 Scalar scalar_add(const Scalar& a, const Scalar& b) const override {
184 return stash(from_stash(a) + from_stash(b));
185 }
186
187 Scalar scalar_sub(const Scalar& a, const Scalar& b) const override {
188 return stash(from_stash(a) - from_stash(b));
189 }
190
191 Scalar scalar_mul(const Scalar& a, const Scalar& b) const override {
192 return stash(from_stash(a) * from_stash(b));
193 }
194
195 Scalar scalar_square(const Scalar& s) const override { return stash(from_stash(s).square()); }
196
197 Scalar scalar_invert(const Scalar& s) const override { return stash(from_stash(s).invert()); }
198
199 Scalar scalar_negate(const Scalar& s) const override { return stash(from_stash(s).negate()); }
200
201 bool scalar_is_zero(const Scalar& s) const override { return from_stash(s).is_zero().as_bool(); }
202
203 bool scalar_equal(const Scalar& a, const Scalar& b) const override {
204 return (from_stash(a) == from_stash(b)).as_bool();
205 }
206
207 Scalar scalar_zero() const override { return stash(C::Scalar::zero()); }
208
209 Scalar scalar_one() const override { return stash(C::Scalar::one()); }
210
211 Scalar scalar_from_u32(uint32_t x) const override { return stash(C::Scalar::from_word(x)); }
212
213 Scalar random_scalar(RandomNumberGenerator& rng) const override { return stash(C::Scalar::random(rng)); }
214
215 PrimeOrderCurveImpl() : m_mul_by_g(C::G) {}
216
217 static std::shared_ptr<const PrimeOrderCurve> instance() {
218 static auto g_curve = std::make_shared<const PrimeOrderCurveImpl<C>>();
219 return g_curve;
220 }
221
222 private:
223 static Scalar stash(const typename C::Scalar& s) {
224 return Scalar::_create(instance(), s.template stash_value<StorageWords>());
225 }
226
227 static typename C::Scalar from_stash(const Scalar& s) {
228 if(s._curve() != instance()) {
229 throw Invalid_Argument("Curve mismatch");
230 }
231 return C::Scalar::from_stash(s._value());
232 }
233
234 static AffinePoint stash(const typename C::AffinePoint& pt) {
235 auto x_w = pt.x().template stash_value<StorageWords>();
236 auto y_w = pt.y().template stash_value<StorageWords>();
237 return AffinePoint::_create(instance(), x_w, y_w);
238 }
239
240 static typename C::AffinePoint from_stash(const AffinePoint& pt) {
241 if(pt._curve() != instance()) {
242 throw Invalid_Argument("Curve mismatch");
243 }
244 auto x = C::FieldElement::from_stash(pt._x());
245 auto y = C::FieldElement::from_stash(pt._y());
246 return typename C::AffinePoint(x, y);
247 }
248
249 static ProjectivePoint stash(const typename C::ProjectivePoint& pt) {
250 auto x_w = pt.x().template stash_value<StorageWords>();
251 auto y_w = pt.y().template stash_value<StorageWords>();
252 auto z_w = pt.z().template stash_value<StorageWords>();
253 return ProjectivePoint::_create(instance(), x_w, y_w, z_w);
254 }
255
256 static typename C::ProjectivePoint from_stash(const ProjectivePoint& pt) {
257 if(pt._curve() != instance()) {
258 throw Invalid_Argument("Curve mismatch");
259 }
260 auto x = C::FieldElement::from_stash(pt._x());
261 auto y = C::FieldElement::from_stash(pt._y());
262 auto z = C::FieldElement::from_stash(pt._z());
263 return typename C::ProjectivePoint(x, y, z);
264 }
265
266 private:
267 const PrecomputedBaseMulTable<C, 5> m_mul_by_g;
268};
269
270} // namespace Botan::PCurve
271
272#endif
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
PrecomputedMul2TableC(const typename C::AffinePoint &x, const typename C::AffinePoint &y)
const WindowedMul2Table< C, WindowBits > & table() const
size_t field_element_bytes() const override
Scalar scalar_zero() const override
bool scalar_equal(const Scalar &a, const Scalar &b) const override
void serialize_scalar(std::span< uint8_t > bytes, const Scalar &scalar) const override
bool affine_point_is_identity(const AffinePoint &pt) const override
Scalar scalar_from_u32(uint32_t x) const override
ProjectivePoint hash_to_curve(std::string_view hash, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep, bool random_oracle) const override
Scalar scalar_sub(const Scalar &a, const Scalar &b) const override
size_t order_bits() const override
Return the bit length of the group order.
void serialize_point_x(std::span< uint8_t > bytes, const AffinePoint &pt) const override
AffinePoint generator() const override
Return the standard generator.
ProjectivePoint mul_by_g(const Scalar &scalar, RandomNumberGenerator &rng) const override
Scalar scalar_from_bits_with_trunc(std::span< const uint8_t > bytes) const override
size_t scalar_bytes() const override
Return the byte length of the scalar element.
bool scalar_is_zero(const Scalar &s) const override
Scalar scalar_invert(const Scalar &s) const override
Scalar scalar_one() const override
ProjectivePoint point_negate(const ProjectivePoint &pt) const override
std::optional< Scalar > mul2_vartime_x_mod_order(const PrecomputedMul2Table &tableb, const Scalar &s1, const Scalar &s2) const override
static std::shared_ptr< const PrimeOrderCurve > instance()
std::optional< Scalar > scalar_from_wide_bytes(std::span< const uint8_t > bytes) const override
std::unique_ptr< const PrecomputedMul2Table > mul2_setup(const AffinePoint &x, const AffinePoint &y) const override
Setup a table for 2-ary multiplication.
Scalar base_point_mul_x_mod_order(const Scalar &scalar, RandomNumberGenerator &rng) const override
ProjectivePoint point_double(const ProjectivePoint &pt) const override
std::optional< Scalar > deserialize_scalar(std::span< const uint8_t > bytes) const override
Scalar scalar_add(const Scalar &a, const Scalar &b) const override
Scalar scalar_negate(const Scalar &s) const override
std::optional< ProjectivePoint > mul2_vartime(const PrecomputedMul2Table &tableb, const Scalar &s1, const Scalar &s2) const override
std::optional< AffinePoint > deserialize_point(std::span< const uint8_t > bytes) const override
Scalar random_scalar(RandomNumberGenerator &rng) const override
ProjectivePoint point_add(const ProjectivePoint &a, const ProjectivePoint &b) const override
void serialize_point(std::span< uint8_t > bytes, const AffinePoint &pt) const override
Scalar scalar_square(const Scalar &s) const override
ProjectivePoint point_to_projective(const AffinePoint &pt) const override
Scalar scalar_mul(const Scalar &a, const Scalar &b) const override
AffinePoint point_to_affine(const ProjectivePoint &pt) const override
ProjectivePoint point_add_mixed(const ProjectivePoint &a, const AffinePoint &b) const override
ProjectivePoint mul(const AffinePoint &pt, const Scalar &scalar, RandomNumberGenerator &rng) const override
void serialize_point_compressed(std::span< uint8_t > bytes, const AffinePoint &pt) const override
static const size_t MaximumBitLength
Definition pcurves.h:37
ProjectivePoint mul(const Scalar &s, RandomNumberGenerator &rng) const
ProjectivePoint mul2_vartime(const Scalar &s1, const Scalar &s2) const
int(* final)(unsigned char *, CTX *)
auto hash_to_curve_sswu(std::string_view hash, bool random_oracle, std::span< const uint8_t > pw, std::span< const uint8_t > dst) -> typename C::ProjectivePoint
BigInt square(const BigInt &x)
Definition numthry.cpp:157