xrpld
Loading...
Searching...
No Matches
SecretKey.cpp
1#include <xrpl/protocol/SecretKey.h>
2
3#include <xrpl/basics/Buffer.h>
4#include <xrpl/basics/Slice.h>
5#include <xrpl/basics/base_uint.h>
6#include <xrpl/basics/contract.h>
7#include <xrpl/basics/strHex.h>
8#include <xrpl/beast/utility/rngfill.h>
9#include <xrpl/crypto/csprng.h>
10#include <xrpl/crypto/secure_erase.h>
11#include <xrpl/protocol/KeyType.h>
12#include <xrpl/protocol/PublicKey.h>
13#include <xrpl/protocol/Seed.h>
14#include <xrpl/protocol/detail/secp256k1.h>
15#include <xrpl/protocol/digest.h>
16#include <xrpl/protocol/tokens.h>
17
18#include <boost/utility/string_view.hpp>
19
20#include <ed25519.h>
21#include <secp256k1.h>
22
23#include <algorithm>
24#include <array>
25#include <cstdint>
26#include <cstring>
27#include <optional>
28#include <stdexcept>
29#include <utility>
30
31namespace xrpl {
32
37
39{
40 std::memcpy(buf_, key.data(), key.size());
41}
42
44{
45 if (slice.size() != sizeof(buf_))
46 logicError("SecretKey::SecretKey: invalid size");
47 std::memcpy(buf_, slice.data(), sizeof(buf_));
48}
49
52{
53 return strHex(*this);
54}
55
56namespace detail {
57
58void
60{
61 *out++ = v >> 24;
62 *out++ = (v >> 16) & 0xff;
63 *out++ = (v >> 8) & 0xff;
64 *out = v & 0xff;
65}
66
69{
70 // We fill this buffer with the seed and append a 32-bit "counter"
71 // that counts how many attempts we've had to make to generate a
72 // non-zero key that's less than the curve's order:
73 //
74 // 1 2
75 // 0 6 0
76 // buf |----------------|----|
77 // | seed | seq|
78
80 std::ranges::copy(seed, buf.begin());
81
82 // The odds that this loop executes more than once are negligible
83 // but *just* in case someone managed to generate a key that required
84 // more iterations loop a few times.
85 for (std::uint32_t seq = 0; seq != 128; ++seq)
86 {
87 copyUInt32(buf.data() + 16, seq);
88
89 auto const ret = sha512Half(buf);
90
91 if (secp256k1_ec_seckey_verify(secp256k1Context(), ret.data()) == 1)
92 {
93 secureErase(buf.data(), buf.size());
94 return ret;
95 }
96 }
97
98 Throw<std::runtime_error>("Unable to derive generator from seed");
99}
100
101//------------------------------------------------------------------------------
121{
122private:
125
126 [[nodiscard]] uint256
128 {
129 // We fill the buffer with the generator, the provided sequence
130 // and a 32-bit counter tracking the number of attempts we have
131 // already made looking for a non-zero key that's less than the
132 // curve's order:
133 // 3 3 4
134 // 0 pubGen 3 7 1
135 // buf |---------------------------------|----|----|
136 // | generator | seq| cnt|
137
140 copyUInt32(buf.data() + 33, seq);
141
142 // The odds that this loop executes more than once are negligible
143 // but we impose a maximum limit just in case.
144 for (std::uint32_t subseq = 0; subseq != 128; ++subseq)
145 {
146 copyUInt32(buf.data() + 37, subseq);
147
148 auto const ret = sha512HalfS(buf);
149
150 if (secp256k1_ec_seckey_verify(secp256k1Context(), ret.data()) == 1)
151 {
152 secureErase(buf.data(), buf.size());
153 return ret;
154 }
155 }
156
157 Throw<std::runtime_error>("Unable to derive generator from seed");
158 }
159
160public:
161 explicit Generator(Seed const& seed) : root_(deriveDeterministicRootKey(seed))
162 {
163 secp256k1_pubkey pubkey;
164 if (secp256k1_ec_pubkey_create(secp256k1Context(), &pubkey, root_.data()) != 1)
165 logicError("derivePublicKey: secp256k1_ec_pubkey_create failed");
166
167 auto len = generator_.size();
168
169 if (secp256k1_ec_pubkey_serialize(
170 secp256k1Context(), generator_.data(), &len, &pubkey, SECP256K1_EC_COMPRESSED) != 1)
171 logicError("derivePublicKey: secp256k1_ec_pubkey_serialize failed");
172 }
173
175 {
176 secureErase(root_.data(), root_.size());
177 secureErase(generator_.data(), generator_.size());
178 }
179
182 operator()(std::size_t ordinal) const
183 {
184 // Generates Nth secret key:
185 auto gsk = [this, tweak = calculateTweak(ordinal)]() {
186 auto rpk = root_;
187
188 if (secp256k1_ec_seckey_tweak_add(secp256k1Context(), rpk.data(), tweak.data()) == 1)
189 {
190 SecretKey const sk{Slice{rpk.data(), rpk.size()}};
191 secureErase(rpk.data(), rpk.size());
192 return sk;
193 }
194
195 logicError("Unable to add a tweak!");
196 }();
197
198 return {derivePublicKey(KeyType::Secp256k1, gsk), gsk};
199 }
200};
201
202} // namespace detail
203
204Buffer
205signDigest(PublicKey const& pk, SecretKey const& sk, uint256 const& digest)
206{
208 logicError("sign: secp256k1 required for digest signing");
209
210 BOOST_ASSERT(sk.size() == 32);
211 secp256k1_ecdsa_signature sigImp;
212 if (secp256k1_ecdsa_sign(
214 &sigImp,
215 reinterpret_cast<unsigned char const*>(digest.data()),
216 reinterpret_cast<unsigned char const*>(sk.data()),
217 secp256k1_nonce_function_rfc6979,
218 nullptr) != 1)
219 logicError("sign: secp256k1_ecdsa_sign failed");
220
221 unsigned char sig[72];
222 size_t len = sizeof(sig);
223 if (secp256k1_ecdsa_signature_serialize_der(secp256k1Context(), sig, &len, &sigImp) != 1)
224 logicError("sign: secp256k1_ecdsa_signature_serialize_der failed");
225
226 return Buffer{sig, len};
227}
228
229Buffer
230sign(PublicKey const& pk, SecretKey const& sk, Slice const& m)
231{
232 auto const type = publicKeyType(pk.slice());
233 if (!type)
234 logicError("sign: invalid type");
235 switch (*type)
236 {
237 case KeyType::Ed25519: {
238 Buffer b(64);
239 ed25519_sign(m.data(), m.size(), sk.data(), pk.data() + 1, b.data());
240 return b;
241 }
242 case KeyType::Secp256k1: {
244 h(m.data(), m.size());
246
247 secp256k1_ecdsa_signature sigImp;
248 if (secp256k1_ecdsa_sign(
250 &sigImp,
251 reinterpret_cast<unsigned char const*>(digest.data()),
252 reinterpret_cast<unsigned char const*>(sk.data()),
253 secp256k1_nonce_function_rfc6979,
254 nullptr) != 1)
255 logicError("sign: secp256k1_ecdsa_sign failed");
256
257 unsigned char sig[72];
258 size_t len = sizeof(sig);
259 if (secp256k1_ecdsa_signature_serialize_der(secp256k1Context(), sig, &len, &sigImp) !=
260 1)
261 logicError("sign: secp256k1_ecdsa_signature_serialize_der failed");
262
263 return Buffer{sig, len};
264 }
265 default:
266 logicError("sign: invalid type");
267 }
268}
269
270SecretKey
272{
273 std::uint8_t buf[32];
274 beast::rngfill(buf, sizeof(buf), cryptoPrng());
275 SecretKey const sk(Slice{buf, sizeof(buf)});
276 secureErase(buf, sizeof(buf));
277 return sk;
278}
279
280SecretKey
282{
283 if (type == KeyType::Ed25519)
284 {
285 auto key = sha512HalfS(Slice(seed.data(), seed.size()));
286 SecretKey const sk{Slice{key.data(), key.size()}};
287 secureErase(key.data(), key.size());
288 return sk;
289 }
290
291 if (type == KeyType::Secp256k1)
292 {
293 auto key = detail::deriveDeterministicRootKey(seed);
294 SecretKey const sk{Slice{key.data(), key.size()}};
295 secureErase(key.data(), key.size());
296 return sk;
297 }
298
299 logicError("generateSecretKey: unknown key type");
300}
301
302PublicKey
304{
305 switch (type)
306 {
307 case KeyType::Secp256k1: {
308 secp256k1_pubkey pubkeyImp;
309 if (secp256k1_ec_pubkey_create(
311 &pubkeyImp,
312 reinterpret_cast<unsigned char const*>(sk.data())) != 1)
313 logicError("derivePublicKey: secp256k1_ec_pubkey_create failed");
314
315 unsigned char pubkey[33];
316 std::size_t len = sizeof(pubkey);
317 if (secp256k1_ec_pubkey_serialize(
318 secp256k1Context(), pubkey, &len, &pubkeyImp, SECP256K1_EC_COMPRESSED) != 1)
319 logicError("derivePublicKey: secp256k1_ec_pubkey_serialize failed");
320
321 return PublicKey{Slice{pubkey, len}};
322 }
323 case KeyType::Ed25519: {
324 unsigned char buf[33];
325 buf[0] = 0xED;
326 ed25519_publickey(sk.data(), &buf[1]);
327 return PublicKey(Slice{buf, sizeof(buf)});
328 }
329 default:
330 logicError("derivePublicKey: bad key type");
331 };
332}
333
335generateKeyPair(KeyType type, Seed const& seed)
336{
337 switch (type)
338 {
339 case KeyType::Secp256k1: {
340 detail::Generator const g(seed);
341 return g(0);
342 }
343 default:
344 case KeyType::Ed25519: {
345 auto const sk = generateSecretKey(type, seed);
346 return {derivePublicKey(type, sk), sk};
347 }
348 }
349}
350
353{
354 auto const sk = randomSecretKey();
355 return {derivePublicKey(type, sk), sk};
356}
357
358template <>
361{
362 auto const result = decodeBase58Token(s, type);
363 if (result.empty())
364 return std::nullopt;
365 if (result.size() != 32)
366 return std::nullopt;
367 return SecretKey(makeSlice(result));
368}
369
370} // namespace xrpl
T begin(T... args)
Like std::vector<char> but better.
Definition Buffer.h:16
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition Buffer.h:129
A public key.
Definition PublicKey.h:42
std::uint8_t const * data() const noexcept
Definition PublicKey.h:67
Slice slice() const noexcept
Definition PublicKey.h:103
A secret key.
Definition SecretKey.h:18
std::size_t size() const
Definition SecretKey.h:50
std::uint8_t const * data() const
Definition SecretKey.h:44
SecretKey()=delete
std::uint8_t buf_[kSize]
Definition SecretKey.h:23
std::string toString() const
Convert the secret key to a hexadecimal string.
Definition SecretKey.cpp:51
Seeds are used to generate deterministic secret keys.
Definition Seed.h:14
std::size_t size() const
Definition Seed.h:45
std::uint8_t const * data() const
Definition Seed.h:39
An immutable linear range of bytes.
Definition Slice.h:26
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition Slice.h:78
std::size_t size() const noexcept
Returns the number of bytes in the storage.
Definition Slice.h:61
Produces a sequence of secp256k1 key pairs.
uint256 calculateTweak(std::uint32_t seq) const
std::pair< PublicKey, SecretKey > operator()(std::size_t ordinal) const
Generate the nth key pair.
Generator(Seed const &seed)
std::array< std::uint8_t, 33 > generator_
T copy(T... args)
T data(T... args)
T memcpy(T... args)
void rngfill(void *const buffer, std::size_t const bytes, Generator &g)
Definition rngfill.h:14
void copyUInt32(std::uint8_t *out, std::uint32_t v)
Definition SecretKey.cpp:59
uint256 deriveDeterministicRootKey(Seed const &seed)
Definition SecretKey.cpp:68
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
detail::BasicSha512HalfHasher< false > sha512_half_hasher
Definition digest.h:194
KeyType
Definition KeyType.h:8
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
static Hasher::result_type digest(void const *data, std::size_t size) noexcept
Definition tokens.cpp:139
void secureErase(void *dest, std::size_t bytes)
Attempts to clear the given blob of memory.
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition digest.h:204
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:10
sha512_half_hasher_s::result_type sha512HalfS(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition digest.h:220
CsprngEngine & cryptoPrng()
The default cryptographically secure PRNG.
SecretKey generateSecretKey(KeyType type, Seed const &seed)
Generate a new secret key deterministically.
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
void logicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
secp256k1_context const * secp256k1Context()
Definition secp256k1.h:9
Buffer signDigest(PublicKey const &pk, SecretKey const &sk, uint256 const &digest)
Generate a signature for a message digest.
TokenType
Definition tokens.h:18
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &message)
Generate a signature for a message.
std::string decodeBase58Token(std::string const &s, TokenType type)
Definition tokens.cpp:188
BaseUInt< 256 > uint256
Definition base_uint.h:562
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Definition contract.h:49
std::enable_if_t< std::is_same_v< T, char >||std::is_same_v< T, unsigned char >, Slice > makeSlice(std::array< T, N > const &a)
Definition Slice.h:215
T size(T... args)