Skip to content

Commit

Permalink
Hide EC Scalar and Point data behind a virtual interface
Browse files Browse the repository at this point in the history
This will allow switching in pcurves later
  • Loading branch information
randombit committed Jul 10, 2024
1 parent 95b80ba commit 2ada5e5
Show file tree
Hide file tree
Showing 14 changed files with 599 additions and 282 deletions.
102 changes: 46 additions & 56 deletions src/lib/pubkey/ec_group/ec_apoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,90 +10,72 @@
#include <botan/ec_scalar.h>
#include <botan/internal/ec_inner_data.h>

#if defined(BOTAN_HAS_EC_HASH_TO_CURVE)
#include <botan/internal/ec_h2c.h>
#endif

namespace Botan {

EC_AffinePoint::EC_AffinePoint(std::shared_ptr<EC_Group_Data> group, std::unique_ptr<EC_Point_Data> point) :
m_group(std::move(group)), m_point(std::move(point)), m_fe_bytes(m_point->field_element_bytes()) {}
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(const EC_AffinePoint& other) :
m_group(other.m_group),
m_point(std::make_unique<EC_Point_Data>(other.m_point->value())),
m_fe_bytes(m_point->field_element_bytes()) {}
EC_AffinePoint::EC_AffinePoint(EC_AffinePoint&& other) noexcept : m_point(std::move(other.m_point)) {}

EC_AffinePoint::EC_AffinePoint(EC_AffinePoint&& other) noexcept :
m_group(std::move(other.m_group)),
m_point(std::move(other.m_point)),
m_fe_bytes(m_point->field_element_bytes()) {}
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) :
m_group(group._data()),
m_point(std::make_unique<EC_Point_Data>(pt)),
m_fe_bytes(m_point->field_element_bytes()) {}
EC_AffinePoint(group, pt.encode(EC_Point_Format::Uncompressed)) {}

EC_AffinePoint::EC_AffinePoint(std::shared_ptr<EC_Group_Data> group, EC_Point&& pt) :
m_group(std::move(group)),
m_point(std::make_unique<EC_Point_Data>(std::move(pt))),
m_fe_bytes(m_point->field_element_bytes()) {}
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) {
#if defined(BOTAN_HAS_EC_HASH_TO_CURVE)
auto pt = hash_to_curve_sswu(group, hash_fn, input, domain_sep, true);
auto v = std::make_unique<EC_Point_Data>(std::move(pt));
return EC_AffinePoint(group._data(), std::move(v));
#else
BOTAN_UNUSED(group, hash_fn, input, domain_sep);
throw Not_Implemented("Hashing to curve not available in this build");
#endif
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) {
#if defined(BOTAN_HAS_EC_HASH_TO_CURVE)
auto pt = hash_to_curve_sswu(group, hash_fn, input, domain_sep, false);
auto v = std::make_unique<EC_Point_Data>(std::move(pt));
return EC_AffinePoint(group._data(), std::move(v));
#else
BOTAN_UNUSED(group, hash_fn, input, domain_sep);
throw Not_Implemented("Hashing to curve not available in this build");
#endif
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) {
try {
auto pt = group.OS2ECP(bytes);
auto v = std::make_unique<EC_Point_Data>(std::move(pt));
return EC_AffinePoint(group._data(), std::move(v));
} catch(...) {
return std::nullopt;
}
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.m_group->blinded_base_point_multiply(scalar.m_scalar->value(), rng, ws);
auto v = std::make_unique<EC_Point_Data>(std::move(pt));
return EC_AffinePoint(scalar.m_group, std::move(v));
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 {
BOTAN_ARG_CHECK(scalar.m_group == m_group, "Curve mismatch");

EC_Point_Var_Point_Precompute mul(m_point->value(), rng, ws);

const auto order = m_group->order() * m_group->cofactor();
auto pt = mul.mul(scalar.m_scalar->value(), rng, order, ws);
auto v = std::make_unique<EC_Point_Data>(std::move(pt));
return EC_AffinePoint(m_group, std::move(v));
return EC_AffinePoint(inner().mul(scalar._inner(), rng, ws));
}

void EC_AffinePoint::serialize_x_to(std::span<uint8_t> bytes) const {
Expand All @@ -117,7 +99,15 @@ void EC_AffinePoint::serialize_uncompressed_to(std::span<uint8_t> bytes) const {
}

EC_Point EC_AffinePoint::to_legacy_point() const {
return m_point->value();
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
32 changes: 24 additions & 8 deletions src/lib/pubkey/ec_group/ec_apoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class EC_Scalar;
class EC_Point;

class EC_Group_Data;
class EC_Point_Data;
class EC_AffinePoint_Data;

class BOTAN_UNSTABLE_API EC_AffinePoint final {
public:
Expand Down Expand Up @@ -60,7 +60,7 @@ class BOTAN_UNSTABLE_API EC_AffinePoint final {
/// 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 { return m_fe_bytes; }
size_t field_element_bytes() const;

/// Write the fixed length encoding of affine x coordinate
///
Expand Down Expand Up @@ -130,21 +130,37 @@ class BOTAN_UNSTABLE_API EC_AffinePoint final {
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);
EC_AffinePoint(const std::shared_ptr<EC_Group_Data>, 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_Data;
friend class EC_Mul2Table;

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

EC_AffinePoint(std::shared_ptr<EC_Group_Data> group, std::unique_ptr<EC_Point_Data> point);
const EC_AffinePoint_Data& inner() const { return *m_point; }

std::shared_ptr<EC_Group_Data> m_group;
std::unique_ptr<EC_Point_Data> m_point;
const size_t m_fe_bytes;
std::unique_ptr<EC_AffinePoint_Data> m_point;
};

} // namespace Botan
Expand Down
58 changes: 15 additions & 43 deletions src/lib/pubkey/ec_group/ec_group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -732,63 +732,35 @@ bool EC_Group::verify_group(RandomNumberGenerator& rng, bool strong) const {
return true;
}

class EC_Mul2Table_Data final {
public:
EC_Mul2Table_Data(std::shared_ptr<EC_Group_Data> group, const EC_Point& g, const EC_Point& h) :
m_group(std::move(group)), m_tbl(g, h) {}

EC_Mul2Table_Data(const EC_AffinePoint& h) :
m_group(h.m_group), m_tbl(h.m_group->base_point(), h.to_legacy_point()) {}

std::optional<EC_AffinePoint> mul2_vartime(const EC_Scalar& x, const EC_Scalar& y) const {
auto pt = m_tbl.multi_exp(x.m_scalar->value(), y.m_scalar->value());

if(pt.is_zero()) {
return std::nullopt;
}
return EC_AffinePoint(m_group, std::move(pt));
}

std::optional<EC_Scalar> mul2_vartime_x_mod_order(const EC_Scalar& x, const EC_Scalar& y) const {
auto pt = m_tbl.multi_exp(x.m_scalar->value(), y.m_scalar->value());

if(pt.is_zero()) {
return std::nullopt;
}
auto v = std::make_unique<EC_Scalar_Data>(m_group->mod_order(pt.get_affine_x()));
return EC_Scalar(m_group, std::move(v));
}

std::optional<EC_Scalar> mul2_vartime_x_mod_order(const EC_Scalar& c,
const EC_Scalar& x,
const EC_Scalar& y) const {
return this->mul2_vartime_x_mod_order(c * x, c * y);
}

private:
std::shared_ptr<EC_Group_Data> m_group;
EC_Point_Multi_Point_Precompute m_tbl;
};

EC_Group::Mul2Table::Mul2Table(const EC_Group& group, const EC_Point& h) :
m_tbl(std::make_unique<EC_Mul2Table_Data>(group.m_data, group.generator(), h)) {}
EC_Group::Mul2Table(EC_AffinePoint(group, h)) {}

EC_Group::Mul2Table::Mul2Table(const EC_AffinePoint& h) : m_tbl(std::make_unique<EC_Mul2Table_Data>(h)) {}
EC_Group::Mul2Table::Mul2Table(const EC_AffinePoint& h) : m_tbl(h._group()->make_mul2_table(h._inner())) {}

EC_Group::Mul2Table::~Mul2Table() = default;

std::optional<EC_AffinePoint> EC_Group::Mul2Table::mul2_vartime(const EC_Scalar& x, const EC_Scalar& y) const {
return m_tbl->mul2_vartime(x, y);
auto pt = m_tbl->mul2_vartime(x._inner(), y._inner());
if(pt) {
return EC_AffinePoint::_from_inner(std::move(pt));
} else {
return {};
}
}

std::optional<EC_Scalar> EC_Group::Mul2Table::mul2_vartime_x_mod_order(const EC_Scalar& x, const EC_Scalar& y) const {
return m_tbl->mul2_vartime_x_mod_order(x, y);
auto s = m_tbl->mul2_vartime_x_mod_order(x._inner(), y._inner());
if(s) {
return EC_Scalar::_from_inner(std::move(s));
} else {
return {};
}
}

std::optional<EC_Scalar> EC_Group::Mul2Table::mul2_vartime_x_mod_order(const EC_Scalar& c,
const EC_Scalar& x,
const EC_Scalar& y) const {
return m_tbl->mul2_vartime_x_mod_order(c, x, y);
return this->mul2_vartime_x_mod_order(c * x, c * y);
}

} // namespace Botan
11 changes: 8 additions & 3 deletions src/lib/pubkey/ec_group/ec_group.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,10 +219,15 @@ class BOTAN_PUBLIC_API(2, 0) EC_Group final {
class Mul2Table final {
public:
/**
* Internal transition function
*
* @warning this will be removed in 3.6.0, NOT COVERED BY SEMVER
*/
Mul2Table(const EC_Group& group, const EC_Point& h);

/**
* Create a table for computing g*x + h*y
*/
Mul2Table(const EC_AffinePoint& h);

/**
Expand Down Expand Up @@ -254,7 +259,7 @@ class BOTAN_PUBLIC_API(2, 0) EC_Group final {
*
* Returns nullopt if g*x*c + h*y*c was the point at infinity
*
* @warning this function is variable time with respect to x and y
* @warning this function is variable time with respect to c, x and y
*/
std::optional<EC_Scalar> mul2_vartime_x_mod_order(const EC_Scalar& c,
const EC_Scalar& x,
Expand Down Expand Up @@ -516,7 +521,7 @@ class BOTAN_PUBLIC_API(2, 0) EC_Group final {
/*
* For internal use only
*/
std::shared_ptr<EC_Group_Data> _data() const { return m_data; }
const std::shared_ptr<EC_Group_Data>& _data() const { return m_data; }

private:
static EC_Group_Data_Map& ec_group_data();
Expand Down
Loading

0 comments on commit 2ada5e5

Please sign in to comment.