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 =
113 boost::multiprecision::number<boost::multiprecision::cpp_int_backend<
114 264,
115 264,
116 boost::multiprecision::signed_magnitude,
117 boost::multiprecision::unchecked,
118 void>>;
119
120 static uint264 const G(
121 "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
122
123 // The format of a signature should be:
124 // <30> <len> [ <02> <lenR> <R> ] [ <02> <lenS> <S> ]
125 if ((sig.size() < 8) || (sig.size() > 72))
126 return std::nullopt;
127 if ((sig[0] != 0x30) || (sig[1] != (sig.size() - 2)))
128 return std::nullopt;
129 Slice p = sig + 2;
130 auto r = sigPart(p);
131 auto s = sigPart(p);
132 if (!r || !s || !p.empty())
133 return std::nullopt;
134
135 uint264 R(sliceToHex(*r));
136 if (R >= G)
137 return std::nullopt;
138
139 uint264 S(sliceToHex(*s));
140 if (S >= G)
141 return std::nullopt;
142
143 // (R,S) and (R,G-S) are canonical,
144 // but is fully canonical when S <= G-S
145 auto const Sp = G - S;
146 if (S > Sp)
149}
150
151static bool
153{
154 if (sig.size() != 64)
155 return false;
156 // Big-endian Order, the Ed25519 subgroup order
157 std::uint8_t const Order[] = {
158 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xDE, 0xF9, 0xDE, 0xA2, 0xF7,
160 0x9C, 0xD6, 0x58, 0x12, 0x63, 0x1A, 0x5C, 0xF5, 0xD3, 0xED,
161 };
162 // Take the second half of signature
163 // and byte-reverse it to big-endian.
164 auto const le = sig.data() + 32;
165 std::uint8_t S[32];
166 std::reverse_copy(le, le + 32, S);
167 // Must be less than Order
168 return std::lexicographical_compare(S, S + 32, Order, Order + 32);
169}
170
171//------------------------------------------------------------------------------
172
174{
175 if (slice.size() < size_)
177 "PublicKey::PublicKey - Input slice cannot be an undersized "
178 "buffer");
179
180 if (!publicKeyType(slice))
181 LogicError("PublicKey::PublicKey invalid type");
183}
184
186{
187 std::memcpy(buf_, other.buf_, size_);
188}
189
192{
193 if (this != &other)
194 {
195 std::memcpy(buf_, other.buf_, size_);
196 }
197
198 return *this;
199}
200
201//------------------------------------------------------------------------------
202
204publicKeyType(Slice const& slice)
205{
206 if (slice.size() == 33)
207 {
208 if (slice[0] == 0xED)
209 return KeyType::ed25519;
210
211 if (slice[0] == 0x02 || slice[0] == 0x03)
212 return KeyType::secp256k1;
213 }
214
215 return std::nullopt;
216}
217
218bool
220 PublicKey const& publicKey,
221 uint256 const& digest,
222 Slice const& sig,
223 bool mustBeFullyCanonical) noexcept
224{
225 if (publicKeyType(publicKey) != KeyType::secp256k1)
226 LogicError("sign: secp256k1 required for digest signing");
227 auto const canonicality = ecdsaCanonicality(sig);
228 if (!canonicality)
229 return false;
230 if (mustBeFullyCanonical &&
231 (*canonicality != ECDSACanonicality::fullyCanonical))
232 return false;
233
234 secp256k1_pubkey pubkey_imp;
235 if (secp256k1_ec_pubkey_parse(
237 &pubkey_imp,
238 reinterpret_cast<unsigned char const*>(publicKey.data()),
239 publicKey.size()) != 1)
240 return false;
241
242 secp256k1_ecdsa_signature sig_imp;
243 if (secp256k1_ecdsa_signature_parse_der(
245 &sig_imp,
246 reinterpret_cast<unsigned char const*>(sig.data()),
247 sig.size()) != 1)
248 return false;
249 if (*canonicality != ECDSACanonicality::fullyCanonical)
250 {
251 secp256k1_ecdsa_signature sig_norm;
252 if (secp256k1_ecdsa_signature_normalize(
253 secp256k1Context(), &sig_norm, &sig_imp) != 1)
254 return false;
255 return secp256k1_ecdsa_verify(
257 &sig_norm,
258 reinterpret_cast<unsigned char const*>(digest.data()),
259 &pubkey_imp) == 1;
260 }
261 return secp256k1_ecdsa_verify(
263 &sig_imp,
264 reinterpret_cast<unsigned char const*>(digest.data()),
265 &pubkey_imp) == 1;
266}
267
268bool
269verify(PublicKey const& publicKey, Slice const& m, Slice const& sig) noexcept
270{
271 if (auto const type = publicKeyType(publicKey))
272 {
273 if (*type == KeyType::secp256k1)
274 {
275 return verifyDigest(publicKey, sha512Half(m), sig);
276 }
277 else if (*type == KeyType::ed25519)
278 {
279 if (!ed25519Canonical(sig))
280 return false;
281
282 // We internally prefix Ed25519 keys with a 0xED
283 // byte to distinguish them from secp256k1 keys
284 // so when verifying the signature, we need to
285 // first strip that prefix.
286 return ed25519_sign_open(
287 m.data(), m.size(), publicKey.data() + 1, sig.data()) ==
288 0;
289 }
290 }
291 return false;
292}
293
294NodeID
296{
297 static_assert(NodeID::bytes == sizeof(ripesha_hasher::result_type));
298
300 h(pk.data(), pk.size());
301 return NodeID{static_cast<ripesha_hasher::result_type>(h)};
302}
303
304} // 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:51
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition Slice.h:79
std::size_t size() const noexcept
Returns the number of bytes in the storage.
Definition Slice.h:62
static std::size_t constexpr bytes
Definition base_uint.h:89
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:138
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:628
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:225
std::string decodeBase58Token(std::string const &s, TokenType type)
Definition tokens.cpp:191
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