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<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 R(sliceToHex(*r));
134 if (R >= G)
135 return std::nullopt;
136
137 uint264 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_)
175 "PublicKey::PublicKey - Input slice cannot be an undersized "
176 "buffer");
177
178 if (!publicKeyType(slice))
179 LogicError("PublicKey::PublicKey invalid type");
181}
182
184{
185 std::memcpy(buf_, other.buf_, size_);
186}
187
190{
191 if (this != &other)
192 {
193 std::memcpy(buf_, other.buf_, size_);
194 }
195
196 return *this;
197}
198
199//------------------------------------------------------------------------------
200
202publicKeyType(Slice const& slice)
203{
204 if (slice.size() == 33)
205 {
206 if (slice[0] == 0xED)
207 return KeyType::ed25519;
208
209 if (slice[0] == 0x02 || slice[0] == 0x03)
210 return KeyType::secp256k1;
211 }
212
213 return std::nullopt;
214}
215
216bool
218 PublicKey const& publicKey,
219 uint256 const& digest,
220 Slice const& sig,
221 bool mustBeFullyCanonical) noexcept
222{
223 if (publicKeyType(publicKey) != KeyType::secp256k1)
224 LogicError("sign: secp256k1 required for digest signing");
225 auto const canonicality = ecdsaCanonicality(sig);
226 if (!canonicality)
227 return false;
228 if (mustBeFullyCanonical && (*canonicality != ECDSACanonicality::fullyCanonical))
229 return false;
230
231 secp256k1_pubkey pubkey_imp;
232 if (secp256k1_ec_pubkey_parse(
234 &pubkey_imp,
235 reinterpret_cast<unsigned char const*>(publicKey.data()),
236 publicKey.size()) != 1)
237 return false;
238
239 secp256k1_ecdsa_signature sig_imp;
240 if (secp256k1_ecdsa_signature_parse_der(
242 &sig_imp,
243 reinterpret_cast<unsigned char const*>(sig.data()),
244 sig.size()) != 1)
245 return false;
246 if (*canonicality != ECDSACanonicality::fullyCanonical)
247 {
248 secp256k1_ecdsa_signature sig_norm;
249 if (secp256k1_ecdsa_signature_normalize(secp256k1Context(), &sig_norm, &sig_imp) != 1)
250 return false;
251 return secp256k1_ecdsa_verify(
253 &sig_norm,
254 reinterpret_cast<unsigned char const*>(digest.data()),
255 &pubkey_imp) == 1;
256 }
257 return secp256k1_ecdsa_verify(
259 &sig_imp,
260 reinterpret_cast<unsigned char const*>(digest.data()),
261 &pubkey_imp) == 1;
262}
263
264bool
265verify(PublicKey const& publicKey, Slice const& m, Slice const& sig) noexcept
266{
267 if (auto const type = publicKeyType(publicKey))
268 {
269 if (*type == KeyType::secp256k1)
270 {
271 return verifyDigest(publicKey, sha512Half(m), sig);
272 }
273 else if (*type == KeyType::ed25519)
274 {
275 if (!ed25519Canonical(sig))
276 return false;
277
278 // We internally prefix Ed25519 keys with a 0xED
279 // byte to distinguish them from secp256k1 keys
280 // so when verifying the signature, we need to
281 // first strip that prefix.
282 return ed25519_sign_open(m.data(), m.size(), publicKey.data() + 1, sig.data()) == 0;
283 }
284 }
285 return false;
286}
287
288NodeID
290{
291 static_assert(NodeID::bytes == sizeof(ripesha_hasher::result_type));
292
294 h(pk.data(), pk.size());
295 return NodeID{static_cast<ripesha_hasher::result_type>(h)};
296}
297
298} // 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:615
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