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