Skip to content

Commit

Permalink
Bridge pcurves to EC_Group/EC_AffinePoint/EC_Scalar
Browse files Browse the repository at this point in the history
  • Loading branch information
randombit committed Jul 12, 2024
1 parent f2d67b2 commit f5c09c6
Show file tree
Hide file tree
Showing 5 changed files with 453 additions and 48 deletions.
163 changes: 116 additions & 47 deletions src/lib/pubkey/ec_group/ec_inner_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@
#include <botan/internal/ec_inner_data.h>

#include <botan/internal/ec_inner_bn.h>

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

namespace Botan {

Expand Down Expand Up @@ -38,7 +36,13 @@ EC_Group_Data::EC_Group_Data(const BigInt& p,
m_a_is_minus_3(a == p - 3),
m_a_is_zero(a.is_zero()),
m_has_cofactor(m_cofactor != 1),
m_source(source) {}
m_source(source) {
if(m_oid.has_value()) {
if(const auto id = PCurve::PrimeOrderCurveId::from_oid(m_oid)) {
m_pcurve = PCurve::PrimeOrderCurve::from_id(*id);
}
}
}

bool EC_Group_Data::params_match(const BigInt& p,
const BigInt& a,
Expand All @@ -56,63 +60,119 @@ bool EC_Group_Data::params_match(const EC_Group_Data& other) const {
}

std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_with_trunc(std::span<const uint8_t> bytes) const {
auto bn = BigInt::from_bytes_with_max_bits(bytes.data(), bytes.size(), m_order_bits);
return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), mod_order(bn));
if(m_pcurve) {
return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_from_bits_with_trunc(bytes));
} else {
auto bn = BigInt::from_bytes_with_max_bits(bytes.data(), bytes.size(), m_order_bits);
return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), mod_order(bn));
}
}

std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bytes_mod_order(std::span<const uint8_t> bytes) const {
BOTAN_ARG_CHECK(bytes.size() <= 2 * order_bytes(), "Input too large");
return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), mod_order(BigInt(bytes)));

if(m_pcurve) {
if(auto s = m_pcurve->scalar_from_wide_bytes(bytes)) {
return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), std::move(*s));
} else {
throw Invalid_Argument("Failed to complete reduction of scalar bytes");
}
} else {
return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), mod_order(BigInt(bytes)));
}
}

std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_random(RandomNumberGenerator& rng) const {
return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::random_integer(rng, BigInt::one(), m_order));
if(m_pcurve) {
return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->random_scalar(rng));
} else {
return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(),
BigInt::random_integer(rng, BigInt::one(), m_order));
}
}

std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_zero() const {
return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::zero());
if(m_pcurve) {
return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_zero());
} else {
return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::zero());
}
}

std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_one() const {
return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::one());
if(m_pcurve) {
return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), m_pcurve->scalar_one());
} else {
return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), BigInt::one());
}
}

std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_from_bigint(const BigInt& bn) const {
// Assumed to have been already checked as in range
return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), bn);
BOTAN_ARG_CHECK(bn >= 0 && bn < m_order, "EC_Scalar BigInt out of range");

if(m_pcurve) {
std::vector<uint8_t> bytes(m_order_bytes);
bn.serialize_to(bytes);
return this->scalar_deserialize(bytes);
} else {
return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), bn);
}
}

std::unique_ptr<EC_Scalar_Data> EC_Group_Data::gk_x_mod_order(const EC_Scalar_Data& scalar,
RandomNumberGenerator& rng,
std::vector<BigInt>& ws) const {
const auto& bn = EC_Scalar_Data_BN::checked_ref(scalar);
const auto pt = m_base_mult.mul(bn.value(), rng, m_order, ws);

if(pt.is_zero()) {
return scalar_zero();
if(m_pcurve) {
const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
auto gk_x_mod_order = m_pcurve->base_point_mul_x_mod_order(k.value(), rng);
return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), gk_x_mod_order);
} else {
return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), mod_order(pt.get_affine_x()));
const auto& k = EC_Scalar_Data_BN::checked_ref(scalar);
const auto pt = m_base_mult.mul(k.value(), rng, m_order, ws);

if(pt.is_zero()) {
return scalar_zero();
} else {
return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), mod_order(pt.get_affine_x()));
}
}
}

std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_deserialize(std::span<const uint8_t> bytes) {
std::unique_ptr<EC_Scalar_Data> EC_Group_Data::scalar_deserialize(std::span<const uint8_t> bytes) const {
if(bytes.size() != m_order_bytes) {
return nullptr;
}

BigInt r(bytes.data(), bytes.size());
if(m_pcurve) {
if(auto s = m_pcurve->deserialize_scalar(bytes)) {
return std::make_unique<EC_Scalar_Data_PC>(shared_from_this(), *s);
} else {
return nullptr;
}
} else {
BigInt r(bytes.data(), bytes.size());

if(r.is_zero() || r >= m_order) {
return nullptr;
}
if(r.is_zero() || r >= m_order) {
return nullptr;
}

return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), std::move(r));
return std::make_unique<EC_Scalar_Data_BN>(shared_from_this(), std::move(r));
}
}

std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_deserialize(std::span<const uint8_t> bytes) const {
try {
auto pt = Botan::OS2ECP(bytes.data(), bytes.size(), curve());
return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
if(m_pcurve) {
auto pt = m_pcurve->deserialize_point(bytes);
if(pt) {
return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(*pt));
} else {
return nullptr;
}
} else {
auto pt = Botan::OS2ECP(bytes.data(), bytes.size(), curve());
return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
}
} catch(...) {
return nullptr;
}
Expand All @@ -121,39 +181,48 @@ std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_deserialize(std::span<
std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_ro(std::string_view hash_fn,
std::span<const uint8_t> input,
std::span<const uint8_t> domain_sep) const {
#if defined(BOTAN_HAS_EC_HASH_TO_CURVE)
auto pt = hash_to_curve_sswu(*this, hash_fn, input, domain_sep, true);
return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
#else
BOTAN_UNUSED(hash_fn, input, domain_sep);
throw Not_Implemented("Hashing to curve not available in this build");
#endif
if(m_pcurve) {
const auto pt = m_pcurve->hash_to_curve(hash_fn, input, domain_sep, true);
return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt.to_affine());
} else {
throw Not_Implemented("Hash to curve is not implemented for this curve");
}
}

std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_hash_to_curve_nu(std::string_view hash_fn,
std::span<const uint8_t> input,
std::span<const uint8_t> domain_sep) const {
#if defined(BOTAN_HAS_EC_HASH_TO_CURVE)
auto pt = hash_to_curve_sswu(*this, hash_fn, input, domain_sep, false);
return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
#else
BOTAN_UNUSED(hash_fn, input, domain_sep);
throw Not_Implemented("Hashing to curve not available in this build");
#endif
if(m_pcurve) {
const auto pt = m_pcurve->hash_to_curve(hash_fn, input, domain_sep, false);
return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), pt.to_affine());
} else {
throw Not_Implemented("Hash to curve is not implemented for this curve");
}
}

std::unique_ptr<EC_AffinePoint_Data> EC_Group_Data::point_g_mul(const EC_Scalar_Data& scalar,
RandomNumberGenerator& rng,
std::vector<BigInt>& ws) const {
const auto& group = scalar.group();
const auto& bn = EC_Scalar_Data_BN::checked_ref(scalar);
auto pt = group->blinded_base_point_multiply(bn.value(), rng, ws);
return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
if(m_pcurve) {
const auto& k = EC_Scalar_Data_PC::checked_ref(scalar);
auto pt = m_pcurve->mul_by_g(k.value(), rng).to_affine();
return std::make_unique<EC_AffinePoint_Data_PC>(shared_from_this(), std::move(pt));
} else {
const auto& group = scalar.group();
const auto& bn = EC_Scalar_Data_BN::checked_ref(scalar);
auto pt = group->blinded_base_point_multiply(bn.value(), rng, ws);
return std::make_unique<EC_AffinePoint_Data_BN>(shared_from_this(), std::move(pt));
}
}

std::unique_ptr<EC_Mul2Table_Data> EC_Group_Data::make_mul2_table(const EC_AffinePoint_Data& h) const {
EC_AffinePoint_Data_BN g(shared_from_this(), this->base_point());
return std::make_unique<EC_Mul2Table_Data_BN>(g, h);
if(m_pcurve) {
EC_AffinePoint_Data_PC g(shared_from_this(), m_pcurve->generator());
return std::make_unique<EC_Mul2Table_Data_PC>(g, h);
} else {
EC_AffinePoint_Data_BN g(shared_from_this(), this->base_point());
return std::make_unique<EC_Mul2Table_Data_BN>(g, h);
}
}

} // namespace Botan
16 changes: 15 additions & 1 deletion src/lib/pubkey/ec_group/ec_inner_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@

namespace Botan {

namespace PCurve {

class PrimeOrderCurve;

}

class EC_Group_Data;

class EC_Scalar_Data {
Expand Down Expand Up @@ -193,7 +199,7 @@ class EC_Group_Data final : public std::enable_shared_from_this<EC_Group_Data> {
RandomNumberGenerator& rng,
std::vector<BigInt>& ws) const;

std::unique_ptr<EC_Scalar_Data> scalar_deserialize(std::span<const uint8_t> bytes);
std::unique_ptr<EC_Scalar_Data> scalar_deserialize(std::span<const uint8_t> bytes) const;

std::unique_ptr<EC_AffinePoint_Data> point_deserialize(std::span<const uint8_t> bytes) const;

Expand All @@ -211,7 +217,15 @@ class EC_Group_Data final : public std::enable_shared_from_this<EC_Group_Data> {

std::unique_ptr<EC_Mul2Table_Data> make_mul2_table(const EC_AffinePoint_Data& pt) const;

const PCurve::PrimeOrderCurve& pcurve() const {
BOTAN_ASSERT_NONNULL(m_pcurve);
return *m_pcurve;
}

private:
// Possibly nullptr (if pcurves not available or not a standard curve)
std::shared_ptr<const PCurve::PrimeOrderCurve> m_pcurve;

CurveGFp m_curve;
EC_Point m_base_point;

Expand Down
Loading

0 comments on commit f5c09c6

Please sign in to comment.