rippled
Loading...
Searching...
No Matches
PublicKey.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpl/basics/contract.h>
21#include <xrpl/basics/strHex.h>
22#include <xrpl/protocol/PublicKey.h>
23#include <xrpl/protocol/detail/secp256k1.h>
24#include <xrpl/protocol/digest.h>
25#include <boost/multiprecision/cpp_int.hpp>
26#include <ed25519.h>
27
28namespace ripple {
29
31operator<<(std::ostream& os, PublicKey const& pk)
32{
33 os << strHex(pk);
34 return os;
35}
36
37template <>
40{
41 auto const result = decodeBase58Token(s, type);
42 auto const pks = makeSlice(result);
43 if (!publicKeyType(pks))
44 return std::nullopt;
45 return PublicKey(pks);
46}
47
48//------------------------------------------------------------------------------
49
50// Parse a length-prefixed number
51// Format: 0x02 <length-byte> <number>
54{
55 if (buf.size() < 3 || buf[0] != 0x02)
56 return std::nullopt;
57 auto const len = buf[1];
58 buf += 2;
59 if (len > buf.size() || len < 1 || len > 33)
60 return std::nullopt;
61 // Can't be negative
62 if ((buf[0] & 0x80) != 0)
63 return std::nullopt;
64 if (buf[0] == 0)
65 {
66 // Can't be zero
67 if (len == 1)
68 return std::nullopt;
69 // Can't be padded
70 if ((buf[1] & 0x80) == 0)
71 return std::nullopt;
72 }
73 std::optional<Slice> number = Slice(buf.data(), len);
74 buf += len;
75 return number;
76}
77
78static std::string
79sliceToHex(Slice const& slice)
80{
82 if (slice[0] & 0x80)
83 {
84 s.reserve(2 * (slice.size() + 2));
85 s = "0x00";
86 }
87 else
88 {
89 s.reserve(2 * (slice.size() + 1));
90 s = "0x";
91 }
92 for (int i = 0; i < slice.size(); ++i)
93 {
94 s += "0123456789ABCDEF"[((slice[i] & 0xf0) >> 4)];
95 s += "0123456789ABCDEF"[((slice[i] & 0x0f) >> 0)];
96 }
97 return s;
98}
99
114{
115 using uint264 =
116 boost::multiprecision::number<boost::multiprecision::cpp_int_backend<
117 264,
118 264,
119 boost::multiprecision::signed_magnitude,
120 boost::multiprecision::unchecked,
121 void>>;
122
123 static uint264 const G(
124 "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
125
126 // The format of a signature should be:
127 // <30> <len> [ <02> <lenR> <R> ] [ <02> <lenS> <S> ]
128 if ((sig.size() < 8) || (sig.size() > 72))
129 return std::nullopt;
130 if ((sig[0] != 0x30) || (sig[1] != (sig.size() - 2)))
131 return std::nullopt;
132 Slice p = sig + 2;
133 auto r = sigPart(p);
134 auto s = sigPart(p);
135 if (!r || !s || !p.empty())
136 return std::nullopt;
137
138 uint264 R(sliceToHex(*r));
139 if (R >= G)
140 return std::nullopt;
141
142 uint264 S(sliceToHex(*s));
143 if (S >= G)
144 return std::nullopt;
145
146 // (R,S) and (R,G-S) are canonical,
147 // but is fully canonical when S <= G-S
148 auto const Sp = G - S;
149 if (S > Sp)
152}
153
154static bool
156{
157 if (sig.size() != 64)
158 return false;
159 // Big-endian Order, the Ed25519 subgroup order
160 std::uint8_t const Order[] = {
161 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xDE, 0xF9, 0xDE, 0xA2, 0xF7,
163 0x9C, 0xD6, 0x58, 0x12, 0x63, 0x1A, 0x5C, 0xF5, 0xD3, 0xED,
164 };
165 // Take the second half of signature
166 // and byte-reverse it to big-endian.
167 auto const le = sig.data() + 32;
168 std::uint8_t S[32];
169 std::reverse_copy(le, le + 32, S);
170 // Must be less than Order
171 return std::lexicographical_compare(S, S + 32, Order, Order + 32);
172}
173
174//------------------------------------------------------------------------------
175
177{
178 if (slice.size() < size_)
180 "PublicKey::PublicKey - Input slice cannot be an undersized "
181 "buffer");
182
183 if (!publicKeyType(slice))
184 LogicError("PublicKey::PublicKey invalid type");
186}
187
189{
190 std::memcpy(buf_, other.buf_, size_);
191}
192
195{
196 if (this != &other)
197 {
198 std::memcpy(buf_, other.buf_, size_);
199 }
200
201 return *this;
202}
203
204//------------------------------------------------------------------------------
205
207publicKeyType(Slice const& slice)
208{
209 if (slice.size() == 33)
210 {
211 if (slice[0] == 0xED)
212 return KeyType::ed25519;
213
214 if (slice[0] == 0x02 || slice[0] == 0x03)
215 return KeyType::secp256k1;
216 }
217
218 return std::nullopt;
219}
220
221bool
223 PublicKey const& publicKey,
224 uint256 const& digest,
225 Slice const& sig,
226 bool mustBeFullyCanonical) noexcept
227{
228 if (publicKeyType(publicKey) != KeyType::secp256k1)
229 LogicError("sign: secp256k1 required for digest signing");
230 auto const canonicality = ecdsaCanonicality(sig);
231 if (!canonicality)
232 return false;
233 if (mustBeFullyCanonical &&
234 (*canonicality != ECDSACanonicality::fullyCanonical))
235 return false;
236
237 secp256k1_pubkey pubkey_imp;
238 if (secp256k1_ec_pubkey_parse(
240 &pubkey_imp,
241 reinterpret_cast<unsigned char const*>(publicKey.data()),
242 publicKey.size()) != 1)
243 return false;
244
245 secp256k1_ecdsa_signature sig_imp;
246 if (secp256k1_ecdsa_signature_parse_der(
248 &sig_imp,
249 reinterpret_cast<unsigned char const*>(sig.data()),
250 sig.size()) != 1)
251 return false;
252 if (*canonicality != ECDSACanonicality::fullyCanonical)
253 {
254 secp256k1_ecdsa_signature sig_norm;
255 if (secp256k1_ecdsa_signature_normalize(
256 secp256k1Context(), &sig_norm, &sig_imp) != 1)
257 return false;
258 return secp256k1_ecdsa_verify(
260 &sig_norm,
261 reinterpret_cast<unsigned char const*>(digest.data()),
262 &pubkey_imp) == 1;
263 }
264 return secp256k1_ecdsa_verify(
266 &sig_imp,
267 reinterpret_cast<unsigned char const*>(digest.data()),
268 &pubkey_imp) == 1;
269}
270
271bool
273 PublicKey const& publicKey,
274 Slice const& m,
275 Slice const& sig,
276 bool mustBeFullyCanonical) noexcept
277{
278 if (auto const type = publicKeyType(publicKey))
279 {
280 if (*type == KeyType::secp256k1)
281 {
282 return verifyDigest(
283 publicKey, sha512Half(m), sig, mustBeFullyCanonical);
284 }
285 else if (*type == KeyType::ed25519)
286 {
287 if (!ed25519Canonical(sig))
288 return false;
289
290 // We internally prefix Ed25519 keys with a 0xED
291 // byte to distinguish them from secp256k1 keys
292 // so when verifying the signature, we need to
293 // first strip that prefix.
294 return ed25519_sign_open(
295 m.data(), m.size(), publicKey.data() + 1, sig.data()) ==
296 0;
297 }
298 }
299 return false;
300}
301
302NodeID
304{
305 static_assert(NodeID::bytes == sizeof(ripesha_hasher::result_type));
306
308 h(pk.data(), pk.size());
309 return NodeID{static_cast<ripesha_hasher::result_type>(h)};
310}
311
312} // namespace ripple
A public key.
Definition: PublicKey.h:62
std::uint8_t const * data() const noexcept
Definition: PublicKey.h:87
std::size_t size() const noexcept
Definition: PublicKey.h:93
static constexpr std::size_t size_
Definition: PublicKey.h:66
std::uint8_t buf_[size_]
Definition: PublicKey.h:67
Slice slice() const noexcept
Definition: PublicKey.h:123
PublicKey & operator=(PublicKey const &other)
Definition: PublicKey.cpp:194
An immutable linear range of bytes.
Definition: Slice.h:45
bool empty() const noexcept
Return true if the byte range is empty.
Definition: Slice.h:69
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition: Slice.h:97
std::size_t size() const noexcept
Returns the number of bytes in the storage.
Definition: Slice.h:80
static std::size_t constexpr bytes
Definition: base_uint.h:107
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:26
secp256k1_context const * secp256k1Context()
Definition: secp256k1.h:29
std::optional< ECDSACanonicality > ecdsaCanonicality(Slice const &sig)
Determines the canonicality of a signature.
Definition: PublicKey.cpp:113
TokenType
Definition: tokens.h:38
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.
Definition: PublicKey.cpp:222
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
Definition: AccountID.cpp:116
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical=true) noexcept
Verify a signature on a message.
Definition: PublicKey.cpp:272
static std::string sliceToHex(Slice const &slice)
Definition: PublicKey.cpp:79
base_uint< 160, detail::NodeIDTag > NodeID
NodeID is a 160-bit hash representing one node.
Definition: UintTypes.h:59
static std::optional< Slice > sigPart(Slice &buf)
Definition: PublicKey.cpp:53
std::ostream & operator<<(std::ostream &out, base_uint< Bits, Tag > const &u)
Definition: base_uint.h:636
std::string decodeBase58Token(std::string const &s, TokenType type)
Definition: tokens.cpp:205
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:207
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
static Hasher::result_type digest(void const *data, std::size_t size) noexcept
Definition: tokens.cpp:152
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:243
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
Definition: PublicKey.cpp:303
static bool ed25519Canonical(Slice const &sig)
Definition: PublicKey.cpp:155
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition: digest.h:223
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
Definition: contract.cpp:48
T reserve(T... args)
T reverse_copy(T... args)
Returns the RIPEMD-160 digest of the SHA256 hash of the message.
Definition: digest.h:135
std::array< std::uint8_t, 20 > result_type
Definition: digest.h:142