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