Skip to content

Commit

Permalink
Merge pull request #4042 from randombit/jack/new-ec-types
Browse files Browse the repository at this point in the history
Add EC_Scalar and EC_AffinePoint types
  • Loading branch information
randombit authored Jul 10, 2024
2 parents 7fad1d2 + 8042e9d commit 45be74e
Show file tree
Hide file tree
Showing 26 changed files with 1,776 additions and 467 deletions.
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

0 comments on commit 45be74e

Please sign in to comment.