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 }
89 std::optional<Slice> number = Slice(buf.data(), len);
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 constexpr char hex[] = "0123456789ABCDEF";
111 s += hex[((slice[i] & 0xf0) >> 4)];
112 s += hex[((slice[i] & 0x0f) >> 0)];
113 }
114 return s;
115}
116
131{
132 using uint264 =
133 boost::multiprecision::number<boost::multiprecision::cpp_int_backend<
134 264,
135 264,
136 boost::multiprecision::signed_magnitude,
137 boost::multiprecision::unchecked,
138 void>>;
139
140 static uint264 const G(
141 "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
142
143 // The format of a signature should be:
144 // <30> <len> [ <02> <lenR> <R> ] [ <02> <lenS> <S> ]
145 if ((sig.size() < 8) || (sig.size() > 72))
146 return std::nullopt;
147 if ((sig[0] != 0x30) || (sig[1] != (sig.size() - 2)))
148 return std::nullopt;
149 Slice p = sig + 2;
150 auto r = sigPart(p);
151 auto s = sigPart(p);
152 if (!r || !s || !p.empty())
153 return std::nullopt;
154
155 uint264 R(sliceToHex(*r));
156 if (R >= G)
157 return std::nullopt;
158
159 uint264 S(sliceToHex(*s));
160 if (S >= G)
161 return std::nullopt;
162
163 // (R,S) and (R,G-S) are canonical,
164 // but is fully canonical when S <= G-S
165 auto const Sp = G - S;
166 if (S > Sp)
169}
170
171static bool
173{
174 if (sig.size() != 64)
175 return false;
176 // Big-endian Order, the Ed25519 subgroup order
177 std::uint8_t const Order[] = {
178 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xDE, 0xF9, 0xDE, 0xA2, 0xF7,
180 0x9C, 0xD6, 0x58, 0x12, 0x63, 0x1A, 0x5C, 0xF5, 0xD3, 0xED,
181 };
182 // Take the second half of signature
183 // and byte-reverse it to big-endian.
184 auto const le = sig.data() + 32;
185 std::uint8_t S[32];
186 std::reverse_copy(le, le + 32, S);
187 // Must be less than Order
188 return std::lexicographical_compare(S, S + 32, Order, Order + 32);
189}
190
191//------------------------------------------------------------------------------
192
194{
195 if (slice.size() < size_)
197 "PublicKey::PublicKey - Input slice cannot be an undersized "
198 "buffer");
199
200 if (!publicKeyType(slice))
201 LogicError("PublicKey::PublicKey invalid type");
203}
204
206{
207 std::memcpy(buf_, other.buf_, size_);
208}
209
212{
213 if (this != &other)
214 {
215 std::memcpy(buf_, other.buf_, size_);
216 }
217
218 return *this;
219}
220
221//------------------------------------------------------------------------------
222
224publicKeyType(Slice const& slice)
225{
226 if (slice.size() == 33)
227 {
228 if (slice[0] == 0xED)
229 return KeyType::ed25519;
230
231 if (slice[0] == 0x02 || slice[0] == 0x03)
232 return KeyType::secp256k1;
233 }
234
235 return std::nullopt;
236}
237
238bool
240 PublicKey const& publicKey,
241 uint256 const& digest,
242 Slice const& sig,
243 bool mustBeFullyCanonical) noexcept
244{
245 if (publicKeyType(publicKey) != KeyType::secp256k1)
246 LogicError("sign: secp256k1 required for digest signing");
247 auto const canonicality = ecdsaCanonicality(sig);
248 if (!canonicality)
249 return false;
250 if (mustBeFullyCanonical &&
251 (*canonicality != ECDSACanonicality::fullyCanonical))
252 return false;
253
254 secp256k1_pubkey pubkey_imp;
255 if (secp256k1_ec_pubkey_parse(
257 &pubkey_imp,
258 reinterpret_cast<unsigned char const*>(publicKey.data()),
259 publicKey.size()) != 1)
260 return false;
261
262 secp256k1_ecdsa_signature sig_imp;
263 if (secp256k1_ecdsa_signature_parse_der(
265 &sig_imp,
266 reinterpret_cast<unsigned char const*>(sig.data()),
267 sig.size()) != 1)
268 return false;
269 if (*canonicality != ECDSACanonicality::fullyCanonical)
270 {
271 secp256k1_ecdsa_signature sig_norm;
272 if (secp256k1_ecdsa_signature_normalize(
273 secp256k1Context(), &sig_norm, &sig_imp) != 1)
274 return false;
275 return secp256k1_ecdsa_verify(
277 &sig_norm,
278 reinterpret_cast<unsigned char const*>(digest.data()),
279 &pubkey_imp) == 1;
280 }
281 return secp256k1_ecdsa_verify(
283 &sig_imp,
284 reinterpret_cast<unsigned char const*>(digest.data()),
285 &pubkey_imp) == 1;
286}
287
288bool
290 PublicKey const& publicKey,
291 Slice const& m,
292 Slice const& sig,
293 bool mustBeFullyCanonical) noexcept
294{
295 if (auto const type = publicKeyType(publicKey))
296 {
297 if (*type == KeyType::secp256k1)
298 {
299 return verifyDigest(
300 publicKey, sha512Half(m), sig, mustBeFullyCanonical);
301 }
302 else if (*type == KeyType::ed25519)
303 {
304 if (!ed25519Canonical(sig))
305 return false;
306
307 // We internally prefix Ed25519 keys with a 0xED
308 // byte to distinguish them from secp256k1 keys
309 // so when verifying the signature, we need to
310 // first strip that prefix.
311 return ed25519_sign_open(
312 m.data(), m.size(), publicKey.data() + 1, sig.data()) ==
313 0;
314 }
315 }
316 return false;
317}
318
319NodeID
321{
322 static_assert(NodeID::bytes == sizeof(ripesha_hasher::result_type));
323
325 h(pk.data(), pk.size());
326 return NodeID{static_cast<ripesha_hasher::result_type>(h)};
327}
328
329} // 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)
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 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:25
secp256k1_context const * secp256k1Context()
Definition secp256k1.h:29
std::optional< ECDSACanonicality > ecdsaCanonicality(Slice const &sig)
Determines the canonicality of a signature.
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.
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: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:647
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.
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.
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:224
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:136
std::array< std::uint8_t, 20 > result_type
Definition digest.h:143