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