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) : root_(deriveDeterministicRootKey(seed))
160 {
161 secp256k1_pubkey pubkey;
162 if (secp256k1_ec_pubkey_create(secp256k1Context(), &pubkey, root_.data()) != 1)
163 LogicError("derivePublicKey: secp256k1_ec_pubkey_create failed");
164
165 auto len = generator_.size();
166
167 if (secp256k1_ec_pubkey_serialize(
168 secp256k1Context(), generator_.data(), &len, &pubkey, SECP256K1_EC_COMPRESSED) != 1)
169 LogicError("derivePublicKey: secp256k1_ec_pubkey_serialize failed");
170 }
171
177
180 operator()(std::size_t ordinal) const
181 {
182 // Generates Nth secret key:
183 auto gsk = [this, tweak = calculateTweak(ordinal)]() {
184 auto rpk = root_;
185
186 if (secp256k1_ec_seckey_tweak_add(secp256k1Context(), rpk.data(), tweak.data()) == 1)
187 {
188 SecretKey sk{Slice{rpk.data(), rpk.size()}};
189 secure_erase(rpk.data(), rpk.size());
190 return sk;
191 }
192
193 LogicError("Unable to add a tweak!");
194 }();
195
196 return {derivePublicKey(KeyType::secp256k1, gsk), gsk};
197 }
198};
199
200} // namespace detail
201
202Buffer
203signDigest(PublicKey const& pk, SecretKey const& sk, uint256 const& digest)
204{
206 LogicError("sign: secp256k1 required for digest signing");
207
208 BOOST_ASSERT(sk.size() == 32);
209 secp256k1_ecdsa_signature sig_imp;
210 if (secp256k1_ecdsa_sign(
212 &sig_imp,
213 reinterpret_cast<unsigned char const*>(digest.data()),
214 reinterpret_cast<unsigned char const*>(sk.data()),
215 secp256k1_nonce_function_rfc6979,
216 nullptr) != 1)
217 LogicError("sign: secp256k1_ecdsa_sign failed");
218
219 unsigned char sig[72];
220 size_t len = sizeof(sig);
221 if (secp256k1_ecdsa_signature_serialize_der(secp256k1Context(), sig, &len, &sig_imp) != 1)
222 LogicError("sign: secp256k1_ecdsa_signature_serialize_der failed");
223
224 return Buffer{sig, len};
225}
226
227Buffer
228sign(PublicKey const& pk, SecretKey const& sk, Slice const& m)
229{
230 auto const type = publicKeyType(pk.slice());
231 if (!type)
232 LogicError("sign: invalid type");
233 switch (*type)
234 {
235 case KeyType::ed25519: {
236 Buffer b(64);
237 ed25519_sign(m.data(), m.size(), sk.data(), pk.data() + 1, b.data());
238 return b;
239 }
240 case KeyType::secp256k1: {
242 h(m.data(), m.size());
244
245 secp256k1_ecdsa_signature sig_imp;
246 if (secp256k1_ecdsa_sign(
248 &sig_imp,
249 reinterpret_cast<unsigned char const*>(digest.data()),
250 reinterpret_cast<unsigned char const*>(sk.data()),
251 secp256k1_nonce_function_rfc6979,
252 nullptr) != 1)
253 LogicError("sign: secp256k1_ecdsa_sign failed");
254
255 unsigned char sig[72];
256 size_t len = sizeof(sig);
257 if (secp256k1_ecdsa_signature_serialize_der(secp256k1Context(), sig, &len, &sig_imp) != 1)
258 LogicError("sign: secp256k1_ecdsa_signature_serialize_der failed");
259
260 return Buffer{sig, len};
261 }
262 default:
263 LogicError("sign: invalid type");
264 }
265}
266
267SecretKey
269{
270 std::uint8_t buf[32];
271 beast::rngfill(buf, sizeof(buf), crypto_prng());
272 SecretKey sk(Slice{buf, sizeof(buf)});
273 secure_erase(buf, sizeof(buf));
274 return sk;
275}
276
277SecretKey
279{
280 if (type == KeyType::ed25519)
281 {
282 auto key = sha512Half_s(Slice(seed.data(), seed.size()));
283 SecretKey sk{Slice{key.data(), key.size()}};
284 secure_erase(key.data(), key.size());
285 return sk;
286 }
287
288 if (type == KeyType::secp256k1)
289 {
290 auto key = detail::deriveDeterministicRootKey(seed);
291 SecretKey sk{Slice{key.data(), key.size()}};
292 secure_erase(key.data(), key.size());
293 return sk;
294 }
295
296 LogicError("generateSecretKey: unknown key type");
297}
298
299PublicKey
301{
302 switch (type)
303 {
304 case KeyType::secp256k1: {
305 secp256k1_pubkey pubkey_imp;
306 if (secp256k1_ec_pubkey_create(
307 secp256k1Context(), &pubkey_imp, reinterpret_cast<unsigned char const*>(sk.data())) != 1)
308 LogicError("derivePublicKey: secp256k1_ec_pubkey_create failed");
309
310 unsigned char pubkey[33];
311 std::size_t len = sizeof(pubkey);
312 if (secp256k1_ec_pubkey_serialize(secp256k1Context(), pubkey, &len, &pubkey_imp, SECP256K1_EC_COMPRESSED) !=
313 1)
314 LogicError("derivePublicKey: secp256k1_ec_pubkey_serialize failed");
315
316 return PublicKey{Slice{pubkey, len}};
317 }
318 case KeyType::ed25519: {
319 unsigned char buf[33];
320 buf[0] = 0xED;
321 ed25519_publickey(sk.data(), &buf[1]);
322 return PublicKey(Slice{buf, sizeof(buf)});
323 }
324 default:
325 LogicError("derivePublicKey: bad key type");
326 };
327}
328
330generateKeyPair(KeyType type, Seed const& seed)
331{
332 switch (type)
333 {
334 case KeyType::secp256k1: {
335 detail::Generator g(seed);
336 return g(0);
337 }
338 default:
339 case KeyType::ed25519: {
340 auto const sk = generateSecretKey(type, seed);
341 return {derivePublicKey(type, sk), sk};
342 }
343 }
344}
345
348{
349 auto const sk = randomSecretKey();
350 return {derivePublicKey(type, sk), sk};
351}
352
353template <>
356{
357 auto const result = decodeBase58Token(s, type);
358 if (result.empty())
359 return std::nullopt;
360 if (result.size() != 32)
361 return std::nullopt;
362 return SecretKey(makeSlice(result));
363}
364
365} // 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:129
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:78
std::size_t size() const noexcept
Returns the number of bytes in the storage.
Definition Slice.h:61
pointer data()
Definition base_uint.h:102
static constexpr std::size_t size()
Definition base_uint.h:495
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:137
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:214
std::string decodeBase58Token(std::string const &s, TokenType type)
Definition tokens.cpp:186
T size(T... args)
Returns the SHA512-Half digest of a message.
Definition digest.h:153