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) != 0)
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<boost::multiprecision::cpp_int_backend<
113 264,
114 264,
115 boost::multiprecision::signed_magnitude,
116 boost::multiprecision::unchecked,
117 void>>;
118
119 static uint264 const G("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
120
121 // The format of a signature should be:
122 // <30> <len> [ <02> <lenR> <R> ] [ <02> <lenS> <S> ]
123 if ((sig.size() < 8) || (sig.size() > 72))
124 return std::nullopt;
125 if ((sig[0] != 0x30) || (sig[1] != (sig.size() - 2)))
126 return std::nullopt;
127 Slice p = sig + 2;
128 auto r = sigPart(p);
129 auto s = sigPart(p);
130 if (!r || !s || !p.empty())
131 return std::nullopt;
132
133 uint264 const R(sliceToHex(*r));
134 if (R >= G)
135 return std::nullopt;
136
137 uint264 const S(sliceToHex(*s));
138 if (S >= G)
139 return std::nullopt;
140
141 // (R,S) and (R,G-S) are canonical,
142 // but is fully canonical when S <= G-S
143 auto const Sp = G - S;
144 if (S > Sp)
147}
148
149static bool
151{
152 if (sig.size() != 64)
153 return false;
154 // Big-endian Order, the Ed25519 subgroup order
155 std::uint8_t const Order[] = {
156 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xDE, 0xF9, 0xDE, 0xA2, 0xF7,
158 0x9C, 0xD6, 0x58, 0x12, 0x63, 0x1A, 0x5C, 0xF5, 0xD3, 0xED,
159 };
160 // Take the second half of signature
161 // and byte-reverse it to big-endian.
162 auto const le = sig.data() + 32;
163 std::uint8_t S[32];
164 std::reverse_copy(le, le + 32, S);
165 // Must be less than Order
166 return std::lexicographical_compare(S, S + 32, Order, Order + 32);
167}
168
169//------------------------------------------------------------------------------
170
172{
173 if (slice.size() < size_)
174 {
176 "PublicKey::PublicKey - Input slice cannot be an undersized "
177 "buffer");
178 }
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 && (*canonicality != ECDSACanonicality::fullyCanonical))
231 return false;
232
233 secp256k1_pubkey pubkey_imp;
234 if (secp256k1_ec_pubkey_parse(
236 &pubkey_imp,
237 reinterpret_cast<unsigned char const*>(publicKey.data()),
238 publicKey.size()) != 1)
239 return false;
240
241 secp256k1_ecdsa_signature sig_imp;
242 if (secp256k1_ecdsa_signature_parse_der(
244 &sig_imp,
245 reinterpret_cast<unsigned char const*>(sig.data()),
246 sig.size()) != 1)
247 return false;
248 if (*canonicality != ECDSACanonicality::fullyCanonical)
249 {
250 secp256k1_ecdsa_signature sig_norm;
251 if (secp256k1_ecdsa_signature_normalize(secp256k1Context(), &sig_norm, &sig_imp) != 1)
252 return false;
253 return secp256k1_ecdsa_verify(
255 &sig_norm,
256 reinterpret_cast<unsigned char const*>(digest.data()),
257 &pubkey_imp) == 1;
258 }
259 return secp256k1_ecdsa_verify(
261 &sig_imp,
262 reinterpret_cast<unsigned char const*>(digest.data()),
263 &pubkey_imp) == 1;
264}
265
266bool
267verify(PublicKey const& publicKey, Slice const& m, Slice const& sig) noexcept
268{
269 if (auto const type = publicKeyType(publicKey))
270 {
271 if (*type == KeyType::secp256k1)
272 {
273 return verifyDigest(publicKey, sha512Half(m), sig);
274 }
275 if (*type == KeyType::ed25519)
276 {
277 if (!ed25519Canonical(sig))
278 return false;
279
280 // We internally prefix Ed25519 keys with a 0xED
281 // byte to distinguish them from secp256k1 keys
282 // so when verifying the signature, we need to
283 // first strip that prefix.
284 return ed25519_sign_open(m.data(), m.size(), publicKey.data() + 1, sig.data()) == 0;
285 }
286 }
287 return false;
288}
289
290NodeID
292{
293 static_assert(NodeID::bytes == sizeof(ripesha_hasher::result_type));
294
296 h(pk.data(), pk.size());
297 return NodeID{static_cast<ripesha_hasher::result_type>(h)};
298}
299
300} // namespace xrpl
A public key.
Definition PublicKey.h:42
std::uint8_t const * data() const noexcept
Definition PublicKey.h:67
std::size_t size() const noexcept
Definition PublicKey.h:73
std::uint8_t buf_[size_]
Definition PublicKey.h:47
Slice slice() const noexcept
Definition PublicKey.h:103
PublicKey()=delete
PublicKey & operator=(PublicKey const &other)
static constexpr std::size_t size_
Definition PublicKey.h:46
An immutable linear range of bytes.
Definition Slice.h:26
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:84
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:5
base_uint< 160, detail::NodeIDTag > NodeID
NodeID is a 160-bit hash representing one node.
Definition UintTypes.h:39
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:204
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:10
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:617
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:9
TokenType
Definition tokens.h:18
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:215
std::string decodeBase58Token(std::string const &s, TokenType type)
Definition tokens.cpp:187
T reserve(T... args)
T reverse_copy(T... args)
Returns the RIPEMD-160 digest of the SHA256 hash of the message.
Definition digest.h:116
std::array< std::uint8_t, 20 > result_type
Definition digest.h:123