Skip to content

Commit

Permalink
Implement draft-irtf-cfrg-hash-to-curve
Browse files Browse the repository at this point in the history
Specifically SSWU with xmd based expansion

Currently only P-256, P-384 and P-521 are supported but in principle
this could be extended to most curves except those with A*B == 0
  • Loading branch information
randombit committed Apr 25, 2021
1 parent 5251aa6 commit 8bf306d
Show file tree
Hide file tree
Showing 15 changed files with 739 additions and 5 deletions.
41 changes: 41 additions & 0 deletions src/cli/speed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,12 @@ class Speed final : public Command
{
bench_os2ecp(ecc_groups, msec);
}
#endif
#if defined(BOTAN_HAS_EC_HASH_TO_CURVE)
else if(algo == "ec_h2c")
{
bench_ec_h2c(msec);
}
#endif
else if(algo == "RNG")
{
Expand Down Expand Up @@ -1223,6 +1229,41 @@ class Speed final : public Command

#endif

#if defined(BOTAN_HAS_EC_HASH_TO_CURVE)
void bench_ec_h2c(const std::chrono::milliseconds runtime)
{
for(std::string group_name : { "secp256r1", "secp384r1", "secp521r1" })
{
auto h2c_ro_timer = make_timer(group_name + "-RO", "", "hash to curve");
auto h2c_nu_timer = make_timer(group_name + "-NU", "", "hash to curve");

const Botan::EC_Group group(group_name);

while(h2c_ro_timer->under(runtime))
{
std::vector<uint8_t> input(32);

rng().randomize(input.data(), input.size());

const Botan::PointGFp p1 = h2c_ro_timer->run([&]() {
return group.hash_to_curve("SHA-256", input.data(), input.size(), nullptr, 0, true);
});

BOTAN_ASSERT_NOMSG(p1.on_the_curve());

const Botan::PointGFp p2 = h2c_nu_timer->run([&]() {
return group.hash_to_curve("SHA-256", input.data(), input.size(), nullptr, 0, false);
});

BOTAN_ASSERT_NOMSG(p2.on_the_curve());
}

record_result(h2c_ro_timer);
record_result(h2c_nu_timer);
}
}
#endif

#if defined(BOTAN_HAS_FPE_FE1)

void bench_fpe_fe1(const std::chrono::milliseconds runtime)
Expand Down
5 changes: 5 additions & 0 deletions src/lib/math/numbertheory/monty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,11 @@ Montgomery_Int Montgomery_Int::square(secure_vector<word>& ws) const
return Montgomery_Int(m_params, m_params->sqr(m_v, ws), false);
}

Montgomery_Int Montgomery_Int::cube(secure_vector<word>& ws) const
{
return Montgomery_Int(m_params, m_params->sqr(m_v, ws), false);
}

Montgomery_Int Montgomery_Int::multiplicative_inverse() const
{
secure_vector<word> ws;
Expand Down
2 changes: 2 additions & 0 deletions src/lib/math/numbertheory/monty.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ class BOTAN_UNSTABLE_API Montgomery_Int final

Montgomery_Int square(secure_vector<word>& ws) const;

Montgomery_Int cube(secure_vector<word>& ws) const;

Montgomery_Int& square_this(secure_vector<word>& ws);

Montgomery_Int& square_this_n_times(secure_vector<word>& ws, size_t n);
Expand Down
7 changes: 7 additions & 0 deletions src/lib/math/numbertheory/reducer.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ class BOTAN_PUBLIC_API(2,0) Modular_Reducer
BigInt multiply(const BigInt& x, const BigInt& y) const
{ return reduce(x * y); }

/**
* Multiply mod p
* @return (x * y * z) % p
*/
BigInt multiply(const BigInt& x, const BigInt& y, const BigInt& z) const
{ return multiply(x, multiply(y, z)); }

/**
* Square mod p
* @param x the value to square
Expand Down
53 changes: 53 additions & 0 deletions src/lib/pubkey/ec_group/ec_group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#include <botan/rng.h>
#include <vector>

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

namespace Botan {

class EC_Group_Data final
Expand Down Expand Up @@ -613,6 +617,15 @@ PointGFp EC_Group::OS2ECP(const uint8_t bits[], size_t len) const

PointGFp EC_Group::point(const BigInt& x, const BigInt& y) const
{
#if 0
BigInt l = (x*x*x + x*get_a() + get_b()) % get_p();
BigInt r = (y*y) % get_p();

if(l != r)
{
printf("invalid point in EC_Group::point\n");
}
#endif
// TODO: randomize the representation?
return PointGFp(data().curve(), x, y);
}
Expand Down Expand Up @@ -660,6 +673,46 @@ PointGFp EC_Group::zero_point() const
return PointGFp(data().curve());
}

PointGFp EC_Group::hash_to_curve(const std::string& hash_fn,
const uint8_t input[],
size_t input_len,
const std::string& domain,
bool random_oracle) const
{
return this->hash_to_curve(hash_fn,
input,
input_len,
reinterpret_cast<const uint8_t*>(domain.c_str()),
domain.size(),
random_oracle);
}

PointGFp EC_Group::hash_to_curve(const std::string& hash_fn,
const uint8_t input[],
size_t input_len,
const uint8_t domain_sep[],
size_t domain_sep_len,
bool random_oracle) const
{
#if defined(BOTAN_HAS_EC_HASH_TO_CURVE)

// Only have SSWU currently
if(get_a().is_zero() || get_b().is_zero() || get_p() % 4 == 1)
{
throw Not_Implemented("EC_Group::hash_to_curve not available for this curve type");
}

return hash_to_curve_sswu(*this, hash_fn,
input, input_len,
domain_sep, domain_sep_len,
random_oracle);

#else
BOTAN_UNUSED(hash_fn, random_oracle, input, input_len, domain_sep, domain_sep_len);
throw Not_Implemented("EC_Group::hash_to_curve functionality not available in this configuration");
#endif
}

std::vector<uint8_t>
EC_Group::DER_encode(EC_Group_Encoding form) const
{
Expand Down
46 changes: 46 additions & 0 deletions src/lib/pubkey/ec_group/ec_group.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,14 @@ class BOTAN_PUBLIC_API(2,0) EC_Group final
*/
BigInt multiply_mod_order(const BigInt& x, const BigInt& y, const BigInt& z) const;

/*
* Return x^3 modulo the order
*/
inline BigInt cube_mod_order(const BigInt& x) const
{
return multiply_mod_order(x, square_mod_order(x));
}

/**
* Check if y is a plausible point on the curve
*
Expand Down Expand Up @@ -290,6 +298,44 @@ class BOTAN_PUBLIC_API(2,0) EC_Group final
*/
BigInt random_scalar(RandomNumberGenerator& rng) const;

/**
* Hash onto the curve.
* For some curve types no mapping is currently available, in this
* case this function will throw an exception.
*
* @param hash_fn the hash function to use (typically "SHA-256" or "SHA-512")
* @param input the input to hash
* @param input_len length of input in bytes
* @param domain_sep a domain seperator
* @param domain_sep_len length of domain_sep in bytes
* @param random_oracle if the mapped point must be uniform (use
"true" here unless you know what you are doing)
*/
PointGFp hash_to_curve(const std::string& hash_fn,
const uint8_t input[],
size_t input_len,
const uint8_t domain_sep[],
size_t domain_sep_len,
bool random_oracle = true) const;

/**
* Hash onto the curve.
* For some curve types no mapping is currently available, in this
* case this function will throw an exception.
*
* @param hash_fn the hash function to use (typically "SHA-256" or "SHA-512")
* @param input the input to hash
* @param input_len length of input in bytes
* @param domain_sep a domain seperator
* @param random_oracle if the mapped point must be uniform (use
"true" here unless you know what you are doing)
*/
PointGFp hash_to_curve(const std::string& hash_fn,
const uint8_t input[],
size_t input_len,
const std::string& domain_sep,
bool random_oracle = true) const;

/**
* Return the zero (or infinite) point on this curve
*/
Expand Down
Loading

0 comments on commit 8bf306d

Please sign in to comment.