Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EC_Scalar and EC_AffinePoint types #4042

Merged
merged 10 commits into from
Jul 10, 2024
Merged
113 changes: 113 additions & 0 deletions src/lib/pubkey/ec_group/ec_apoint.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* (C) 2024 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/ec_apoint.h>

#include <botan/ec_group.h>
#include <botan/ec_scalar.h>
#include <botan/internal/ec_inner_data.h>

namespace Botan {

EC_AffinePoint::EC_AffinePoint(std::unique_ptr<EC_AffinePoint_Data> point) : m_point(std::move(point)) {
BOTAN_ASSERT_NONNULL(m_point);
}

EC_AffinePoint::EC_AffinePoint(const EC_AffinePoint& other) : m_point(other.inner().clone()) {}

EC_AffinePoint::EC_AffinePoint(EC_AffinePoint&& other) noexcept : m_point(std::move(other.m_point)) {}

EC_AffinePoint& EC_AffinePoint::operator=(const EC_AffinePoint& other) {
if(this != &other) {
m_point = other.inner().clone();
}
return (*this);
}

EC_AffinePoint& EC_AffinePoint::operator=(EC_AffinePoint&& other) noexcept {
m_point.swap(other.m_point);
return (*this);
}

EC_AffinePoint::EC_AffinePoint(const EC_Group& group, std::span<const uint8_t> bytes) {
m_point = group._data()->point_deserialize(bytes);
if(!m_point) {
throw Decoding_Error("Failed to deserialize elliptic curve point");
}
}

EC_AffinePoint::EC_AffinePoint(const EC_Group& group, const EC_Point& pt) :
EC_AffinePoint(group, pt.encode(EC_Point_Format::Uncompressed)) {}

size_t EC_AffinePoint::field_element_bytes() const {
return inner().field_element_bytes();
}

EC_AffinePoint EC_AffinePoint::hash_to_curve_ro(const EC_Group& group,
std::string_view hash_fn,
std::span<const uint8_t> input,
std::span<const uint8_t> domain_sep) {
auto pt = group._data()->point_hash_to_curve_ro(hash_fn, input, domain_sep);
return EC_AffinePoint(std::move(pt));
}

EC_AffinePoint EC_AffinePoint::hash_to_curve_nu(const EC_Group& group,
std::string_view hash_fn,
std::span<const uint8_t> input,
std::span<const uint8_t> domain_sep) {
auto pt = group._data()->point_hash_to_curve_nu(hash_fn, input, domain_sep);
return EC_AffinePoint(std::move(pt));
}

EC_AffinePoint::~EC_AffinePoint() = default;

std::optional<EC_AffinePoint> EC_AffinePoint::deserialize(const EC_Group& group, std::span<const uint8_t> bytes) {
auto pt = group._data()->point_deserialize(bytes);
return EC_AffinePoint(std::move(pt));
}

EC_AffinePoint EC_AffinePoint::g_mul(const EC_Scalar& scalar, RandomNumberGenerator& rng, std::vector<BigInt>& ws) {
auto pt = scalar._inner().group()->point_g_mul(scalar.inner(), rng, ws);
return EC_AffinePoint(std::move(pt));
}

EC_AffinePoint EC_AffinePoint::mul(const EC_Scalar& scalar, RandomNumberGenerator& rng, std::vector<BigInt>& ws) const {
return EC_AffinePoint(inner().mul(scalar._inner(), rng, ws));
}

void EC_AffinePoint::serialize_x_to(std::span<uint8_t> bytes) const {
m_point->serialize_x_to(bytes);
}

void EC_AffinePoint::serialize_y_to(std::span<uint8_t> bytes) const {
m_point->serialize_y_to(bytes);
}

void EC_AffinePoint::serialize_xy_to(std::span<uint8_t> bytes) const {
m_point->serialize_xy_to(bytes);
}

void EC_AffinePoint::serialize_compressed_to(std::span<uint8_t> bytes) const {
m_point->serialize_compressed_to(bytes);
}

void EC_AffinePoint::serialize_uncompressed_to(std::span<uint8_t> bytes) const {
m_point->serialize_uncompressed_to(bytes);
}

EC_Point EC_AffinePoint::to_legacy_point() const {
return m_point->to_legacy_point();
}

EC_AffinePoint EC_AffinePoint::_from_inner(std::unique_ptr<EC_AffinePoint_Data> inner) {
return EC_AffinePoint(std::move(inner));
}

const std::shared_ptr<const EC_Group_Data>& EC_AffinePoint::_group() const {
return inner().group();
}

} // namespace Botan
168 changes: 168 additions & 0 deletions src/lib/pubkey/ec_group/ec_apoint.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*
* (C) 2024 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#ifndef BOTAN_EC_APOINT_H_
#define BOTAN_EC_APOINT_H_

#include <botan/concepts.h>
#include <botan/secmem.h>
#include <botan/types.h>
#include <optional>
#include <span>
#include <string_view>
#include <vector>

namespace Botan {

class BigInt;
class RandomNumberGenerator;
class EC_Group;
class EC_Scalar;
class EC_Point;

class EC_Group_Data;
class EC_AffinePoint_Data;

class BOTAN_UNSTABLE_API EC_AffinePoint final {
public:
/// Point deserialization. Returns nullopt if wrong length or not a valid point
static std::optional<EC_AffinePoint> deserialize(const EC_Group& group, std::span<const uint8_t> bytes);

/// Multiply by the group generator returning a complete point
///
/// Workspace argument is transitional
static EC_AffinePoint g_mul(const EC_Scalar& scalar, RandomNumberGenerator& rng, std::vector<BigInt>& ws);

/// Hash to curve (RFC 9380), random oracle variant
///
/// Only supported for specific groups
static EC_AffinePoint hash_to_curve_ro(const EC_Group& group,
std::string_view hash_fn,
std::span<const uint8_t> input,
std::span<const uint8_t> domain_sep);

/// Hash to curve (RFC 9380), non uniform variant
///
/// Only supported for specific groups
static EC_AffinePoint hash_to_curve_nu(const EC_Group& group,
std::string_view hash_fn,
std::span<const uint8_t> input,
std::span<const uint8_t> domain_sep);

/// Multiply a point by a scalar returning a complete point
///
/// Workspace argument is transitional
EC_AffinePoint mul(const EC_Scalar& scalar, RandomNumberGenerator& rng, std::vector<BigInt>& ws) const;

/// Return the number of bytes of a field element
///
/// A point consists of two field elements, plus possibly a header
size_t field_element_bytes() const;

/// Write the fixed length encoding of affine x coordinate
///
/// The output span must be exactly field_element_bytes long
void serialize_x_to(std::span<uint8_t> bytes) const;

/// Write the fixed length encoding of affine y coordinate
///
/// The output span must be exactly field_element_bytes long
void serialize_y_to(std::span<uint8_t> bytes) const;

/// Write the fixed length encoding of affine x and y coordinates
///
/// The output span must be exactly 2*field_element_bytes long
void serialize_xy_to(std::span<uint8_t> bytes) const;

/// Write the fixed length SEC1 compressed encoding
///
/// The output span must be exactly 1 + field_element_bytes long
void serialize_compressed_to(std::span<uint8_t> bytes) const;

/// Return the fixed length encoding of SEC1 uncompressed encoding
///
/// The output span must be exactly 1 + 2*field_element_bytes long
void serialize_uncompressed_to(std::span<uint8_t> bytes) const;

/// Return the bytes of the affine x coordinate in a container
template <concepts::resizable_byte_buffer T = secure_vector<uint8_t>>
T x_bytes() const {
T bytes(this->field_element_bytes());
this->serialize_x_to(bytes);
return bytes;
}

/// Return the bytes of the affine y coordinate in a container
template <concepts::resizable_byte_buffer T = secure_vector<uint8_t>>
T y_bytes() const {
T bytes(this->field_element_bytes());
this->serialize_y_to(bytes);
return bytes;
}

/// Return the bytes of the affine x and y coordinates in a container
template <concepts::resizable_byte_buffer T = secure_vector<uint8_t>>
T xy_bytes() const {
T bytes(2 * this->field_element_bytes());
this->serialize_xy_to(bytes);
return bytes;
}

/// Return the bytes of the affine x and y coordinates in a container
template <concepts::resizable_byte_buffer T = std::vector<uint8_t>>
T serialize_uncompressed() const {
T bytes(1 + 2 * this->field_element_bytes());
this->serialize_uncompressed_to(bytes);
return bytes;
}

/// Return the bytes of the affine x and y coordinates in a container
template <concepts::resizable_byte_buffer T = std::vector<uint8_t>>
T serialize_compressed() const {
T bytes(1 + this->field_element_bytes());
this->serialize_compressed_to(bytes);
return bytes;
}

EC_AffinePoint(const EC_AffinePoint& other);
EC_AffinePoint(EC_AffinePoint&& other) noexcept;

EC_AffinePoint& operator=(const EC_AffinePoint& other);
EC_AffinePoint& operator=(EC_AffinePoint&& other) noexcept;

EC_AffinePoint(const EC_Group& group, std::span<const uint8_t> bytes);

/**
* Deprecated conversion
*/
EC_AffinePoint(const EC_Group& group, const EC_Point& pt);

/**
* Deprecated conversion
*/
EC_Point to_legacy_point() const;

~EC_AffinePoint();

const EC_AffinePoint_Data& _inner() const { return inner(); }

static EC_AffinePoint _from_inner(std::unique_ptr<EC_AffinePoint_Data> inner);

const std::shared_ptr<const EC_Group_Data>& _group() const;

private:
friend class EC_Mul2Table;

EC_AffinePoint(std::unique_ptr<EC_AffinePoint_Data> point);

const EC_AffinePoint_Data& inner() const { return *m_point; }

std::unique_ptr<EC_AffinePoint_Data> m_point;
};

} // namespace Botan

#endif
Loading
Loading