Files
xahaud/include/xrpl/protocol/PublicKey.h
Alphonse Mousse 62ac6a562c Various fixes:
- Fix unlikely edge case in setCurrentThreadName
    setCurrentThreadName accepts a std::string_view parameter, which is
    not guaranteed to include a null terminator, which it then forwards
    to OS-specific APIs that expect null-terminated C strings.
- Fix several compilation warnings
- Fix header includes
- Fix unnecessarily verbose logging
- Simplify code using inline lambdas instead of std::bind
- Modernize the Beast "lexical cast" framework
- Use boost::asio types instead of legacy Beast type wrappers
- Clean up LogicError, custom exception throwing and termination handling
- Clean up and modernize PublicKey, SecretKey and Seed
    Simplify construction, buffer iteration and comparisons by leveraging
    modern C++ features.
- Clean up and modernize RFC1751 code
    Turn static-member-only class into namespace, thin out the public API
    and make code noexcept and constexpr. Verify internal data at compile
    time.
- Clean up CSPRNG engine
- Clean up rngfill function, eliminating GCC false-positive warning.
- Improve Slice comparison using C++ operator<=> and operator synthesis.
2026-09-23 13:03:28 +10:00

253 lines
6.7 KiB
C++

//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_PROTOCOL_PUBLICKEY_H_INCLUDED
#define RIPPLE_PROTOCOL_PUBLICKEY_H_INCLUDED
#include <xrpl/basics/Slice.h>
#include <xrpl/protocol/KeyType.h>
#include <xrpl/protocol/STExchange.h>
#include <xrpl/protocol/UintTypes.h>
#include <xrpl/protocol/detail/KeyBase.h>
#include <xrpl/protocol/json_get_or_throw.h>
#include <xrpl/protocol/tokens.h>
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <optional>
#include <ostream>
#include <utility>
namespace ripple {
/** Returns the type of public key.
@return std::nullopt If the public key does not
represent a known type.
*/
[[nodiscard]] inline std::optional<KeyType>
publicKeyType(Slice const& slice)
{
if (slice.size() == 33)
{
if (slice[0] == 0xED)
return KeyType::ed25519;
if (slice[0] == 0x02 || slice[0] == 0x03)
return KeyType::secp256k1;
}
return std::nullopt;
}
/** A public key.
Public keys are used in the public-key cryptography
system used to verify signatures attached to messages.
The format of the public key is Ripple specific,
information needed to determine the cryptosystem
parameters used is stored inside the key.
As of this writing two systems are supported:
secp256k1
ed25519
secp256k1 public keys consist of a 33 byte
compressed public key, with the lead byte equal
to 0x02 or 0x03.
The ed25519 public keys consist of a 1 byte
prefix constant 0xED, followed by 32 bytes of
public key data.
*/
class PublicKey : public detail::KeyBase<PublicKey, 33>
{
public:
PublicKey() = delete;
PublicKey(PublicKey const&) = default;
PublicKey&
operator=(PublicKey const&) = default;
explicit PublicKey(Slice const& slice) noexcept
{
if (slice.size() < buf_.size())
LogicError("PublicKey::PublicKey: undersized buffer");
if (!publicKeyType(slice))
LogicError("PublicKey::PublicKey: invalid type");
std::copy_n(slice.data(), buf_.size(), buf_.data());
}
explicit PublicKey(value_t const& data) noexcept
: PublicKey(makeSlice(data))
{
}
[[nodiscard]] Slice
slice() const noexcept
{
return {buf_.data(), buf_.size()};
}
operator Slice() const noexcept
{
return slice();
}
[[nodiscard]] auto
operator<=>(PublicKey const& rhs) const
{
return buf_ <=> rhs.buf_;
}
};
/** Print the public key to a stream.
*/
std::ostream&
operator<<(std::ostream& os, PublicKey const& pk);
template <class Hasher>
void
hash_append(Hasher& h, PublicKey const& pk)
{
h(pk.data(), pk.size());
}
template <>
struct STExchange<STBlob, PublicKey>
{
explicit STExchange() = default;
using value_type = PublicKey;
static void
get(std::optional<value_type>& t, STBlob const& u)
{
t.emplace(Slice(u.data(), u.size()));
}
static std::unique_ptr<STBlob>
set(SField const& f, PublicKey const& t)
{
return std::make_unique<STBlob>(f, t.data(), t.size());
}
};
//------------------------------------------------------------------------------
inline std::string
toBase58(TokenType type, PublicKey const& pk)
{
return encodeBase58Token(type, pk.data(), pk.size());
}
template <>
std::optional<PublicKey>
parseBase58(TokenType type, std::string const& s);
enum class ECDSACanonicality { canonical, fullyCanonical };
/** Determines the canonicality of a signature.
A canonical signature is in its most reduced form.
For example the R and S components do not contain
additional leading zeroes. However, even in
canonical form, (R,S) and (R,G-S) are both
valid signatures for message M.
Therefore, to prevent malleability attacks we
define a fully canonical signature as one where:
R < G - S
where G is the curve order.
This routine returns std::nullopt if the format
of the signature is invalid (for example, the
points are encoded incorrectly).
@return std::nullopt if the signature fails
validity checks.
@note Only the format of the signature is checked,
no verification cryptography is performed.
*/
std::optional<ECDSACanonicality>
ecdsaCanonicality(Slice const& sig);
/** Verify a secp256k1 signature on the digest of a message. */
[[nodiscard]] bool
verifyDigest(
PublicKey const& publicKey,
uint256 const& digest,
Slice const& sig,
bool mustBeFullyCanonical = true) noexcept;
/** Verify a signature on a message.
With secp256k1 signatures, the data is first hashed with
SHA512-Half, and the resulting digest is signed.
*/
[[nodiscard]] bool
verify(
PublicKey const& publicKey,
Slice const& m,
Slice const& sig,
bool mustBeFullyCanonical = true) noexcept;
/** Calculate the 160-bit node ID from a node public key. */
NodeID
calcNodeID(PublicKey const&);
// VFALCO This belongs in AccountID.h but
// is here because of header issues
AccountID
calcAccountID(PublicKey const& pk);
} // namespace ripple
//------------------------------------------------------------------------------
namespace Json {
template <>
inline ripple::PublicKey
getOrThrow(Json::Value const& v, ripple::SField const& field)
{
using namespace ripple;
std::string const b58 = getOrThrow<std::string>(v, field);
if (auto pubKeyBlob = strUnHex(b58); publicKeyType(makeSlice(*pubKeyBlob)))
{
return PublicKey{makeSlice(*pubKeyBlob)};
}
for (auto const tokenType :
{TokenType::NodePublic, TokenType::AccountPublic})
{
if (auto const pk = parseBase58<PublicKey>(tokenType, b58))
return *pk;
}
Throw<JsonTypeMismatchError>(field.getJsonName(), "PublicKey");
}
} // namespace Json
#endif