rippled
Loading...
Searching...
No Matches
PublicKey.cpp
1#include <xrpl/basics/Slice.h>
2#include <xrpl/basics/base_uint.h>
3#include <xrpl/basics/contract.h>
4#include <xrpl/basics/strHex.h>
5#include <xrpl/protocol/KeyType.h>
6#include <xrpl/protocol/PublicKey.h>
7#include <xrpl/protocol/UintTypes.h>
8#include <xrpl/protocol/detail/secp256k1.h>
9#include <xrpl/protocol/digest.h>
10#include <xrpl/protocol/tokens.h>
11
12#include <boost/multiprecision/fwd.hpp>
13#include <boost/multiprecision/number.hpp>
14
15#include <ed25519.h>
16
17#include <algorithm>
18#include <cstdint>
19#include <cstring>
20#include <optional>
21#include <ostream>
22#include <string>
23
24namespace xrpl {
25
27operator<<(std::ostream& os, PublicKey const& pk)
28{
29 os << strHex(pk);
30 return os;
31}
32
33template <>
36{
37 auto const result = decodeBase58Token(s, type);
38 auto const pks = makeSlice(result);
39 if (!publicKeyType(pks))
40 return std::nullopt;
41 return PublicKey(pks);
42}
43
44//------------------------------------------------------------------------------
45
46// Parse a length-prefixed number
47// Format: 0x02 <length-byte> <number>
50{
51 if (buf.size() < 3 || buf[0] != 0x02)
52 return std::nullopt;
53 auto const len = buf[1];
54 buf += 2;
55 if (len > buf.size() || len < 1 || len > 33)
56 return std::nullopt;
57 // Can't be negative
58 if ((buf[0] & 0x80) != 0)
59 return std::nullopt;
60 if (buf[0] == 0)
61 {
62 // Can't be zero
63 if (len == 1)
64 return std::nullopt;
65 // Can't be padded
66 if ((buf[1] & 0x80) == 0)
67 return std::nullopt;
68 }
69 std::optional<Slice> number = Slice(buf.data(), len);
70 buf += len;
71 return number;
72}
73
74static std::string
75sliceToHex(Slice const& slice)
76{
78 if (slice[0] & 0x80)
79 {
80 s.reserve(2 * (slice.size() + 2));
81 s = "0x00";
82 }
83 else
84 {
85 s.reserve(2 * (slice.size() + 1));
86 s = "0x";
87 }
88 for (int i = 0; i < slice.size(); ++i)
89 {
90 constexpr char hex[] = "0123456789ABCDEF";
91 s += hex[((slice[i] & 0xf0) >> 4)];
92 s += hex[((slice[i] & 0x0f) >> 0)];
93 }
94 return s;
95}
96
111{
112 using uint264 = boost::multiprecision::number<
113 boost::multiprecision::
114 cpp_int_backend<264, 264, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
115
116 static uint264 const G("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
117
118 // The format of a signature should be:
119 // <30> <len> [ <02> <lenR> <R> ] [ <02> <lenS> <S> ]
120 if ((sig.size() < 8) || (sig.size() > 72))
121 return std::nullopt;
122 if ((sig[0] != 0x30) || (sig[1] != (sig.size() - 2)))
123 return std::nullopt;
124 Slice p = sig + 2;
125 auto r = sigPart(p);
126 auto s = sigPart(p);
127 if (!r || !s || !p.empty())
128 return std::nullopt;
129
130 uint264 R(sliceToHex(*r));
131 if (R >= G)
132 return std::nullopt;
133
134 uint264 S(sliceToHex(*s));
135 if (S >= G)
136 return std::nullopt;
137
138 // (R,S) and (R,G-S) are canonical,
139 // but is fully canonical when S <= G-S
140 auto const Sp = G - S;
141 if (S > Sp)
144}
145
146static bool
148{
149 if (sig.size() != 64)
150 return false;
151 // Big-endian Order, the Ed25519 subgroup order
152 std::uint8_t const Order[] = {
153 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154 0x14, 0xDE, 0xF9, 0xDE, 0xA2, 0xF7, 0x9C, 0xD6, 0x58, 0x12, 0x63, 0x1A, 0x5C, 0xF5, 0xD3, 0xED,
155 };
156 // Take the second half of signature
157 // and byte-reverse it to big-endian.
158 auto const le = sig.data() + 32;
159 std::uint8_t S[32];
160 std::reverse_copy(le, le + 32, S);
161 // Must be less than Order
162 return std::lexicographical_compare(S, S + 32, Order, Order + 32);
163}
164
165//------------------------------------------------------------------------------
166
168{
169 if (slice.size() < size_)
171 "PublicKey::PublicKey - Input slice cannot be an undersized "
172 "buffer");
173
174 if (!publicKeyType(slice))
175 LogicError("PublicKey::PublicKey invalid type");
177}
178
180{
181 std::memcpy(buf_, other.buf_, size_);
182}
183
186{
187 if (this != &other)
188 {
189 std::memcpy(buf_, other.buf_, size_);
190 }
191
192 return *this;
193}
194
195//------------------------------------------------------------------------------
196
198publicKeyType(Slice const& slice)
199{
200 if (slice.size() == 33)
201 {
202 if (slice[0] == 0xED)
203 return KeyType::ed25519;
204
205 if (slice[0] == 0x02 || slice[0] == 0x03)
206 return KeyType::secp256k1;
207 }
208
209 return std::nullopt;
210}
211
212bool
213verifyDigest(PublicKey const& publicKey, uint256 const& digest, Slice const& sig, bool mustBeFullyCanonical) noexcept
214{
215 if (publicKeyType(publicKey) != KeyType::secp256k1)
216 LogicError("sign: secp256k1 required for digest signing");
217 auto const canonicality = ecdsaCanonicality(sig);
218 if (!canonicality)
219 return false;
220 if (mustBeFullyCanonical && (*canonicality != ECDSACanonicality::fullyCanonical))
221 return false;
222
223 secp256k1_pubkey pubkey_imp;
224 if (secp256k1_ec_pubkey_parse(
226 &pubkey_imp,
227 reinterpret_cast<unsigned char const*>(publicKey.data()),
228 publicKey.size()) != 1)
229 return false;
230
231 secp256k1_ecdsa_signature sig_imp;
232 if (secp256k1_ecdsa_signature_parse_der(
233 secp256k1Context(), &sig_imp, reinterpret_cast<unsigned char const*>(sig.data()), sig.size()) != 1)
234 return false;
235 if (*canonicality != ECDSACanonicality::fullyCanonical)
236 {
237 secp256k1_ecdsa_signature sig_norm;
238 if (secp256k1_ecdsa_signature_normalize(secp256k1Context(), &sig_norm, &sig_imp) != 1)
239 return false;
240 return secp256k1_ecdsa_verify(
241 secp256k1Context(), &sig_norm, reinterpret_cast<unsigned char const*>(digest.data()), &pubkey_imp) ==
242 1;
243 }
244 return secp256k1_ecdsa_verify(
245 secp256k1Context(), &sig_imp, reinterpret_cast<unsigned char const*>(digest.data()), &pubkey_imp) == 1;
246}
247
248bool
249verify(PublicKey const& publicKey, Slice const& m, Slice const& sig) noexcept
250{
251 if (auto const type = publicKeyType(publicKey))
252 {
253 if (*type == KeyType::secp256k1)
254 {
255 return verifyDigest(publicKey, sha512Half(m), sig);
256 }
257 else if (*type == KeyType::ed25519)
258 {
259 if (!ed25519Canonical(sig))
260 return false;
261
262 // We internally prefix Ed25519 keys with a 0xED
263 // byte to distinguish them from secp256k1 keys
264 // so when verifying the signature, we need to
265 // first strip that prefix.
266 return ed25519_sign_open(m.data(), m.size(), publicKey.data() + 1, sig.data()) == 0;
267 }
268 }
269 return false;
270}
271
272NodeID
274{
275 static_assert(NodeID::bytes == sizeof(ripesha_hasher::result_type));
276
278 h(pk.data(), pk.size());
279 return NodeID{static_cast<ripesha_hasher::result_type>(h)};
280}
281
282} // namespace xrpl
A public key.
Definition PublicKey.h:43
std::uint8_t const * data() const noexcept
Definition PublicKey.h:68
std::size_t size() const noexcept
Definition PublicKey.h:74
std::uint8_t buf_[size_]
Definition PublicKey.h:48
Slice slice() const noexcept
Definition PublicKey.h:104
PublicKey()=delete
PublicKey & operator=(PublicKey const &other)
static constexpr std::size_t size_
Definition PublicKey.h:47
An immutable linear range of bytes.
Definition Slice.h:27
bool empty() const noexcept
Return true if the byte range is empty.
Definition Slice.h:50
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition Slice.h:78
std::size_t size() const noexcept
Returns the number of bytes in the storage.
Definition Slice.h:61
static std::size_t constexpr bytes
Definition base_uint.h:85
T is_same_v
T lexicographical_compare(T... args)
T memcpy(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
base_uint< 160, detail::NodeIDTag > NodeID
NodeID is a 160-bit hash representing one node.
Definition UintTypes.h:40
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
static Hasher::result_type digest(void const *data, std::size_t size) noexcept
Definition tokens.cpp:137
static bool ed25519Canonical(Slice const &sig)
bool verifyDigest(PublicKey const &publicKey, uint256 const &digest, Slice const &sig, bool mustBeFullyCanonical=true) noexcept
Verify a secp256k1 signature on the digest of a message.
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition digest.h:205
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:11
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig) noexcept
Verify a signature on a message.
std::optional< ECDSACanonicality > ecdsaCanonicality(Slice const &sig)
Determines the canonicality of a signature.
std::ostream & operator<<(std::ostream &out, base_uint< Bits, Tag > const &u)
Definition base_uint.h:613
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
static std::optional< Slice > sigPart(Slice &buf)
Definition PublicKey.cpp:49
secp256k1_context const * secp256k1Context()
Definition secp256k1.h:10
TokenType
Definition tokens.h:19
static std::string sliceToHex(Slice const &slice)
Definition PublicKey.cpp:75
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition Slice.h:214
std::string decodeBase58Token(std::string const &s, TokenType type)
Definition tokens.cpp:186
T reserve(T... args)
T reverse_copy(T... args)
Returns the RIPEMD-160 digest of the SHA256 hash of the message.
Definition digest.h:117
std::array< std::uint8_t, 20 > result_type
Definition digest.h:124