7#ifndef BOTAN_PCURVES_WRAP_H_
8#define BOTAN_PCURVES_WRAP_H_
10#include <botan/exceptn.h>
11#include <botan/internal/pcurves.h>
12#include <botan/internal/pcurves_impl.h>
18 { C::scalar_invert(s) } -> std::same_as<typename C::Scalar>;
32 size_t order_bits()
const override {
return C::OrderBits; }
39 return stash(m_mul_by_g.mul(from_stash(scalar), rng));
44 return stash(tbl.mul(from_stash(scalar), rng));
53 pt_x.serialize_to(std::span<uint8_t, C::FieldElement::BYTES>{x_bytes});
59 const auto&
table()
const {
return m_table; }
69 return std::make_unique<PrecomputedMul2TableC>(C::G, from_stash(q));
74 const Scalar& y)
const override {
77 auto pt = table.
table().mul2_vartime(from_stash(x), from_stash(y));
78 if(pt.is_identity().as_bool()) {
83 }
catch(std::bad_cast&) {
94 auto pt = tbl.
mul2(from_stash(x), from_stash(y), rng);
95 if(pt.is_identity().as_bool()) {
105 const Scalar& y)
const override {
108 const auto pt = table.
table().mul2_vartime(from_stash(x), from_stash(y));
110 if(pt.is_identity().as_bool()) {
127 const auto z2 = pt.z().square();
129 std::array<uint8_t, C::Scalar::BYTES> v_bytes{};
130 from_stash(v).serialize_to(v_bytes);
132 if(
const auto fe_v = C::FieldElement::deserialize(v_bytes)) {
133 if((*fe_v * z2 == pt.x()).as_bool()) {
148 if constexpr(C::OrderIsLessThanField) {
163 const auto n = C::FieldElement::from_words(C::NW);
164 const auto neg_n = n.negate().to_words();
166 const auto vw = fe_v->to_words();
167 if(
bigint_ct_is_lt(vw.data(), vw.size(), neg_n.data(), neg_n.size()).as_bool()) {
168 return (((*fe_v + n) * z2) == pt.x()).as_bool();
174 }
catch(std::bad_cast&) {
180 auto pt = m_mul_by_g.mul(from_stash(scalar), rng);
181 std::array<uint8_t, C::FieldElement::BYTES> x_bytes{};
184 return stash(C::Scalar::from_wide_bytes(std::span<const uint8_t, C::FieldElement::BYTES>{x_bytes}));
192 const auto y2 = affine.y().square();
193 const auto x3_ax_b = C::x3_ax_b(affine.x());
194 const auto valid_point = affine.is_identity() || (y2 == x3_ax_b);
196 BOTAN_ASSERT(valid_point.as_bool(),
"Computed point is on the curve");
198 return stash(affine);
202 return stash(C::ProjectivePoint::from_affine(from_stash(a)) + from_stash(b));
208 return from_stash(pt).is_identity().as_bool();
212 BOTAN_ARG_CHECK(bytes.size() == C::AffinePoint::BYTES,
"Invalid length for serialize_point");
213 from_stash(pt).serialize_to(bytes.subspan<0, C::AffinePoint::BYTES>());
217 BOTAN_ARG_CHECK(bytes.size() == C::Scalar::BYTES,
"Invalid length to serialize_scalar");
218 return from_stash(scalar).serialize_to(bytes.subspan<0, C::Scalar::BYTES>());
222 if(
auto scalar = C::Scalar::deserialize(bytes)) {
223 if(!scalar->is_zero().as_bool()) {
224 return stash(*scalar);
232 if(
auto s = C::Scalar::from_wide_bytes_varlen(bytes)) {
242 if(bytes.size() == 1 && bytes[0] == 0x00) {
243 return stash(C::AffinePoint::identity());
246 constexpr size_t FieldElementBytes = C::FieldElement::BYTES;
247 constexpr size_t CompressedBytes = C::FieldElement::BYTES + 1;
248 constexpr size_t UncompressedBytes = 2 * C::FieldElement::BYTES + 1;
250 if(bytes.size() == UncompressedBytes && bytes[0] == 0x04) {
251 const auto encoded_point = bytes.subspan(1);
252 auto x = C::FieldElement::deserialize(encoded_point.first(FieldElementBytes));
253 auto y = C::FieldElement::deserialize(encoded_point.last(FieldElementBytes));
257 const auto lhs = (*y).square();
258 const auto rhs = C::x3_ax_b(*x);
259 const auto valid = (lhs == rhs);
260 if(valid.as_bool()) {
261 return stash(
typename C::AffinePoint(*x, *y));
264 }
else if(bytes.size() == CompressedBytes && (bytes[0] == 0x02 || bytes[0] == 0x03)) {
267 if(
auto x = C::FieldElement::deserialize(bytes.subspan(1, FieldElementBytes))) {
269 return stash(
typename C::AffinePoint(*x, y->correct_sign(y_is_even)));
278 if constexpr(C::ValidForSswuHash) {
281 throw Not_Implemented(
"Hash to curve is not implemented for this curve");
286 if constexpr(C::ValidForSswuHash) {
289 throw Not_Implemented(
"Hash to curve is not implemented for this curve");
294 return stash(from_stash(a) + from_stash(b));
298 return stash(from_stash(a) - from_stash(b));
302 return stash(from_stash(a) * from_stash(b));
308 auto s = from_stash(ss);
310 return stash(C::scalar_invert(s));
312 return stash(s.invert());
317 auto s = from_stash(ss);
318 return stash(s.invert_vartime());
326 return (from_stash(a) == from_stash(b)).as_bool();
335 static std::shared_ptr<const PrimeOrderCurve>
instance() {
336 static auto g_curve = std::make_shared<const PrimeOrderCurveImpl<C>>();
341 static Scalar stash(
const typename C::Scalar& s) {
342 return Scalar::_create(
instance(), s.template stash_value<StorageWords>());
345 static typename C::Scalar from_stash(
const Scalar& s) {
349 return C::Scalar::from_stash(s._value());
352 static AffinePoint stash(
const typename C::AffinePoint& pt) {
353 auto x_w = pt.x().template stash_value<StorageWords>();
354 auto y_w = pt.y().template stash_value<StorageWords>();
355 return AffinePoint::_create(
instance(), x_w, y_w);
358 static typename C::AffinePoint from_stash(
const AffinePoint& pt) {
360 throw Invalid_Argument(
"Curve mismatch");
362 auto x = C::FieldElement::from_stash(pt._x());
363 auto y = C::FieldElement::from_stash(pt._y());
364 return typename C::AffinePoint(x, y);
368 auto x_w = pt.x().template stash_value<StorageWords>();
369 auto y_w = pt.y().template stash_value<StorageWords>();
370 auto z_w = pt.z().template stash_value<StorageWords>();
371 return ProjectivePoint::_create(
instance(), x_w, y_w, z_w);
374 static typename C::ProjectivePoint from_stash(
const ProjectivePoint& pt) {
376 throw Invalid_Argument(
"Curve mismatch");
378 auto x = C::FieldElement::from_stash(pt._x());
379 auto y = C::FieldElement::from_stash(pt._y());
380 auto z = C::FieldElement::from_stash(pt._z());
381 return typename C::ProjectivePoint(x, y, z);
385 const PrecomputedBaseMulTable<C, BasePointWindowBits> m_mul_by_g;
#define BOTAN_ARG_CHECK(expr, msg)
#define BOTAN_ASSERT(expr, assertion_made)
static constexpr Mask< T > is_equal(T x, T y)
PrecomputedMul2TableC(const typename C::AffinePoint &x, const typename C::AffinePoint &y)
const auto & table() const
AffinePoint point_negate(const AffinePoint &pt) const override
Scalar scalar_invert(const Scalar &ss) const override
Scalar inversion.
size_t field_element_bytes() const override
std::unique_ptr< const PrecomputedMul2Table > mul2_setup_g(const AffinePoint &q) const override
Setup a table for 2-ary multiplication where the first point is the generator.
bool scalar_equal(const Scalar &a, const Scalar &b) const override
Test if two scalars are equal.
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_sub(const Scalar &a, const Scalar &b) const override
Scalar subtraction.
size_t order_bits() const override
Return the bit length of the group order.
AffinePoint generator() const override
Return the standard generator.
ProjectivePoint mul_by_g(const Scalar &scalar, RandomNumberGenerator &rng) const override
size_t scalar_bytes() const override
Return the byte length of the scalar element.
AffinePoint hash_to_curve_nu(std::function< void(std::span< uint8_t >)> expand_message) const override
bool scalar_is_zero(const Scalar &s) const override
Test if scalar is zero.
Scalar scalar_one() const override
static std::shared_ptr< const PrimeOrderCurve > instance()
std::optional< Scalar > scalar_from_wide_bytes(std::span< const uint8_t > bytes) const override
ProjectivePoint hash_to_curve_ro(std::function< void(std::span< uint8_t >)> expand_message) const override
Scalar base_point_mul_x_mod_order(const Scalar &scalar, RandomNumberGenerator &rng) 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 addition.
Scalar scalar_negate(const Scalar &s) const override
Scalar negation.
Scalar scalar_invert_vartime(const Scalar &ss) const override
Scalar inversion (variable time)
bool mul2_vartime_x_mod_order_eq(const PrecomputedMul2Table &tableb, const Scalar &v, const Scalar &x, const Scalar &y) const override
ProjectivePoint point_add(const AffinePoint &a, const AffinePoint &b) const override
std::optional< AffinePoint > deserialize_point(std::span< const uint8_t > bytes) const override
Scalar random_scalar(RandomNumberGenerator &rng) const override
void serialize_point(std::span< uint8_t > bytes, const AffinePoint &pt) const override
Scalar scalar_square(const Scalar &s) const override
Scalar squaring.
secure_vector< uint8_t > mul_x_only(const AffinePoint &pt, const Scalar &scalar, RandomNumberGenerator &rng) const override
Scalar scalar_mul(const Scalar &a, const Scalar &b) const override
Scalar multiplication.
AffinePoint point_to_affine(const ProjectivePoint &pt) const override
std::optional< ProjectivePoint > mul2_vartime(const PrecomputedMul2Table &tableb, const Scalar &x, const Scalar &y) const override
ProjectivePoint mul(const AffinePoint &pt, const Scalar &scalar, RandomNumberGenerator &rng) const override
std::optional< ProjectivePoint > mul_px_qy(const AffinePoint &p, const Scalar &x, const AffinePoint &q, const Scalar &y, RandomNumberGenerator &rng) const override
static constexpr size_t MaximumBitLength
ProjectivePoint mul2(const Scalar &s1, const Scalar &s2, RandomNumberGenerator &rng) const
auto to_affine_x(const typename C::ProjectivePoint &pt)
constexpr CT::Option< typename C::FieldElement > sqrt_field_element(const typename C::FieldElement &fe)
BigInt square(const BigInt &x)
auto hash_to_curve_sswu(const ExpandMsg &expand_message) -> std::conditional_t< RO, typename C::ProjectivePoint, typename C::AffinePoint >
constexpr auto to_affine(const typename C::ProjectivePoint &pt)
constexpr auto bigint_ct_is_lt(const W x[], size_t x_size, const W y[], size_t y_size, bool lt_or_equal=false) -> CT::Mask< W >
std::vector< T, secure_allocator< T > > secure_vector