rippled
Loading...
Searching...
No Matches
SecretKey.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/Buffer.h>
21#include <xrpl/basics/Slice.h>
22#include <xrpl/basics/base_uint.h>
23#include <xrpl/basics/contract.h>
24#include <xrpl/basics/strHex.h>
25#include <xrpl/beast/utility/rngfill.h>
26#include <xrpl/crypto/csprng.h>
27#include <xrpl/crypto/secure_erase.h>
28#include <xrpl/protocol/KeyType.h>
29#include <xrpl/protocol/PublicKey.h>
30#include <xrpl/protocol/SecretKey.h>
31#include <xrpl/protocol/Seed.h>
32#include <xrpl/protocol/detail/secp256k1.h>
33#include <xrpl/protocol/digest.h>
34#include <xrpl/protocol/tokens.h>
35
36#include <boost/utility/string_view.hpp>
37
38#include <ed25519.h>
39#include <secp256k1.h>
40
41#include <algorithm>
42#include <array>
43#include <cstdint>
44#include <cstring>
45#include <optional>
46#include <stdexcept>
47#include <utility>
48
49namespace ripple {
50
55
60
62{
63 if (slice.size() != sizeof(buf_))
64 LogicError("SecretKey::SecretKey: invalid size");
65 std::memcpy(buf_, slice.data(), sizeof(buf_));
66}
67
70{
71 return strHex(*this);
72}
73
74namespace detail {
75
76void
78{
79 *out++ = v >> 24;
80 *out++ = (v >> 16) & 0xff;
81 *out++ = (v >> 8) & 0xff;
82 *out = v & 0xff;
83}
84
87{
88 // We fill this buffer with the seed and append a 32-bit "counter"
89 // that counts how many attempts we've had to make to generate a
90 // non-zero key that's less than the curve's order:
91 //
92 // 1 2
93 // 0 6 0
94 // buf |----------------|----|
95 // | seed | seq|
96
98 std::copy(seed.begin(), seed.end(), buf.begin());
99
100 // The odds that this loop executes more than once are neglible
101 // but *just* in case someone managed to generate a key that required
102 // more iterations loop a few times.
103 for (std::uint32_t seq = 0; seq != 128; ++seq)
104 {
105 copy_uint32(buf.data() + 16, seq);
106
107 auto const ret = sha512Half(buf);
108
109 if (secp256k1_ec_seckey_verify(secp256k1Context(), ret.data()) == 1)
110 {
111 secure_erase(buf.data(), buf.size());
112 return ret;
113 }
114 }
115
116 Throw<std::runtime_error>("Unable to derive generator from seed");
117}
118
119//------------------------------------------------------------------------------
139{
140private:
143
144 uint256
146 {
147 // We fill the buffer with the generator, the provided sequence
148 // and a 32-bit counter tracking the number of attempts we have
149 // already made looking for a non-zero key that's less than the
150 // curve's order:
151 // 3 3 4
152 // 0 pubGen 3 7 1
153 // buf |---------------------------------|----|----|
154 // | generator | seq| cnt|
155
158 copy_uint32(buf.data() + 33, seq);
159
160 // The odds that this loop executes more than once are neglible
161 // but we impose a maximum limit just in case.
162 for (std::uint32_t subseq = 0; subseq != 128; ++subseq)
163 {
164 copy_uint32(buf.data() + 37, subseq);
165
166 auto const ret = sha512Half_s(buf);
167
168 if (secp256k1_ec_seckey_verify(secp256k1Context(), ret.data()) == 1)
169 {
170 secure_erase(buf.data(), buf.size());
171 return ret;
172 }
173 }
174
175 Throw<std::runtime_error>("Unable to derive generator from seed");
176 }
177
178public:
179 explicit Generator(Seed const& seed)
181 {
182 secp256k1_pubkey pubkey;
183 if (secp256k1_ec_pubkey_create(
184 secp256k1Context(), &pubkey, root_.data()) != 1)
185 LogicError("derivePublicKey: secp256k1_ec_pubkey_create failed");
186
187 auto len = generator_.size();
188
189 if (secp256k1_ec_pubkey_serialize(
192 &len,
193 &pubkey,
194 SECP256K1_EC_COMPRESSED) != 1)
195 LogicError("derivePublicKey: secp256k1_ec_pubkey_serialize failed");
196 }
197
203
206 operator()(std::size_t ordinal) const
207 {
208 // Generates Nth secret key:
209 auto gsk = [this, tweak = calculateTweak(ordinal)]() {
210 auto rpk = root_;
211
212 if (secp256k1_ec_seckey_tweak_add(
213 secp256k1Context(), rpk.data(), tweak.data()) == 1)
214 {
215 SecretKey sk{Slice{rpk.data(), rpk.size()}};
216 secure_erase(rpk.data(), rpk.size());
217 return sk;
218 }
219
220 LogicError("Unable to add a tweak!");
221 }();
222
223 return {derivePublicKey(KeyType::secp256k1, gsk), gsk};
224 }
225};
226
227} // namespace detail
228
229Buffer
230signDigest(PublicKey const& pk, SecretKey const& sk, uint256 const& digest)
231{
233 LogicError("sign: secp256k1 required for digest signing");
234
235 BOOST_ASSERT(sk.size() == 32);
236 secp256k1_ecdsa_signature sig_imp;
237 if (secp256k1_ecdsa_sign(
239 &sig_imp,
240 reinterpret_cast<unsigned char const*>(digest.data()),
241 reinterpret_cast<unsigned char const*>(sk.data()),
242 secp256k1_nonce_function_rfc6979,
243 nullptr) != 1)
244 LogicError("sign: secp256k1_ecdsa_sign failed");
245
246 unsigned char sig[72];
247 size_t len = sizeof(sig);
248 if (secp256k1_ecdsa_signature_serialize_der(
249 secp256k1Context(), sig, &len, &sig_imp) != 1)
250 LogicError("sign: secp256k1_ecdsa_signature_serialize_der failed");
251
252 return Buffer{sig, len};
253}
254
255Buffer
256sign(PublicKey const& pk, SecretKey const& sk, Slice const& m)
257{
258 auto const type = publicKeyType(pk.slice());
259 if (!type)
260 LogicError("sign: invalid type");
261 switch (*type)
262 {
263 case KeyType::ed25519: {
264 Buffer b(64);
265 ed25519_sign(
266 m.data(), m.size(), sk.data(), pk.data() + 1, b.data());
267 return b;
268 }
269 case KeyType::secp256k1: {
271 h(m.data(), m.size());
273
274 secp256k1_ecdsa_signature sig_imp;
275 if (secp256k1_ecdsa_sign(
277 &sig_imp,
278 reinterpret_cast<unsigned char const*>(digest.data()),
279 reinterpret_cast<unsigned char const*>(sk.data()),
280 secp256k1_nonce_function_rfc6979,
281 nullptr) != 1)
282 LogicError("sign: secp256k1_ecdsa_sign failed");
283
284 unsigned char sig[72];
285 size_t len = sizeof(sig);
286 if (secp256k1_ecdsa_signature_serialize_der(
287 secp256k1Context(), sig, &len, &sig_imp) != 1)
289 "sign: secp256k1_ecdsa_signature_serialize_der failed");
290
291 return Buffer{sig, len};
292 }
293 default:
294 LogicError("sign: invalid type");
295 }
296}
297
298SecretKey
300{
301 std::uint8_t buf[32];
302 beast::rngfill(buf, sizeof(buf), crypto_prng());
303 SecretKey sk(Slice{buf, sizeof(buf)});
304 secure_erase(buf, sizeof(buf));
305 return sk;
306}
307
308SecretKey
310{
311 if (type == KeyType::ed25519)
312 {
313 auto key = sha512Half_s(Slice(seed.data(), seed.size()));
314 SecretKey sk{Slice{key.data(), key.size()}};
315 secure_erase(key.data(), key.size());
316 return sk;
317 }
318
319 if (type == KeyType::secp256k1)
320 {
321 auto key = detail::deriveDeterministicRootKey(seed);
322 SecretKey sk{Slice{key.data(), key.size()}};
323 secure_erase(key.data(), key.size());
324 return sk;
325 }
326
327 LogicError("generateSecretKey: unknown key type");
328}
329
330PublicKey
332{
333 switch (type)
334 {
335 case KeyType::secp256k1: {
336 secp256k1_pubkey pubkey_imp;
337 if (secp256k1_ec_pubkey_create(
339 &pubkey_imp,
340 reinterpret_cast<unsigned char const*>(sk.data())) != 1)
342 "derivePublicKey: secp256k1_ec_pubkey_create failed");
343
344 unsigned char pubkey[33];
345 std::size_t len = sizeof(pubkey);
346 if (secp256k1_ec_pubkey_serialize(
348 pubkey,
349 &len,
350 &pubkey_imp,
351 SECP256K1_EC_COMPRESSED) != 1)
353 "derivePublicKey: secp256k1_ec_pubkey_serialize failed");
354
355 return PublicKey{Slice{pubkey, len}};
356 }
357 case KeyType::ed25519: {
358 unsigned char buf[33];
359 buf[0] = 0xED;
360 ed25519_publickey(sk.data(), &buf[1]);
361 return PublicKey(Slice{buf, sizeof(buf)});
362 }
363 default:
364 LogicError("derivePublicKey: bad key type");
365 };
366}
367
369generateKeyPair(KeyType type, Seed const& seed)
370{
371 switch (type)
372 {
373 case KeyType::secp256k1: {
374 detail::Generator g(seed);
375 return g(0);
376 }
377 default:
378 case KeyType::ed25519: {
379 auto const sk = generateSecretKey(type, seed);
380 return {derivePublicKey(type, sk), sk};
381 }
382 }
383}
384
387{
388 auto const sk = randomSecretKey();
389 return {derivePublicKey(type, sk), sk};
390}
391
392template <>
395{
396 auto const result = decodeBase58Token(s, type);
397 if (result.empty())
398 return std::nullopt;
399 if (result.size() != 32)
400 return std::nullopt;
401 return SecretKey(makeSlice(result));
402}
403
404} // namespace ripple
T begin(T... args)
Like std::vector<char> but better.
Definition Buffer.h:36
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition Buffer.h:151
A public key.
Definition PublicKey.h:62
std::uint8_t const * data() const noexcept
Definition PublicKey.h:87
Slice slice() const noexcept
Definition PublicKey.h:123
A secret key.
Definition SecretKey.h:38
std::uint8_t const * data() const
Definition SecretKey.h:56
std::size_t size() const
Definition SecretKey.h:62
std::uint8_t buf_[32]
Definition SecretKey.h:40
std::string to_string() const
Convert the secret key to a hexadecimal string.
Definition SecretKey.cpp:69
Seeds are used to generate deterministic secret keys.
Definition Seed.h:34
std::size_t size() const
Definition Seed.h:65
const_iterator end() const noexcept
Definition Seed.h:83
const_iterator begin() const noexcept
Definition Seed.h:71
std::uint8_t const * data() const
Definition Seed.h:59
An immutable linear range of bytes.
Definition Slice.h:46
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 constexpr std::size_t size()
Definition base_uint.h:526
Produces a sequence of secp256k1 key pairs.
uint256 calculateTweak(std::uint32_t seq) const
std::array< std::uint8_t, 33 > generator_
std::pair< PublicKey, SecretKey > operator()(std::size_t ordinal) const
Generate the nth key pair.
Generator(Seed const &seed)
T copy(T... args)
T data(T... args)
T end(T... args)
T is_same_v
T memcpy(T... args)
void rngfill(void *const buffer, std::size_t const bytes, Generator &g)
Definition rngfill.h:34
void copy_uint32(std::uint8_t *out, std::uint32_t v)
Definition SecretKey.cpp:77
uint256 deriveDeterministicRootKey(Seed const &seed)
Definition SecretKey.cpp:86
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
sha512_half_hasher_s::result_type sha512Half_s(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition digest.h:240
TokenType
Definition tokens.h:38
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
csprng_engine & crypto_prng()
The default cryptographically secure PRNG.
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
SecretKey generateSecretKey(KeyType type, Seed const &seed)
Generate a new secret key deterministically.
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: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
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
KeyType
Definition KeyType.h:28
Buffer signDigest(PublicKey const &pk, SecretKey const &sk, uint256 const &digest)
Generate a signature for a message digest.
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
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.
void secure_erase(void *dest, std::size_t bytes)
Attempts to clear the given blob of memory.
T size(T... args)
Returns the SHA512-Half digest of a message.
Definition digest.h:172