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