xrpld
Loading...
Searching...
No Matches
Seed_test.cpp
1#include <xrpl/basics/Slice.h>
2#include <xrpl/basics/base_uint.h>
3#include <xrpl/basics/random.h>
4#include <xrpl/beast/unit_test/suite.h>
5#include <xrpl/beast/utility/rngfill.h>
6#include <xrpl/protocol/AccountID.h>
7#include <xrpl/protocol/KeyType.h>
8#include <xrpl/protocol/PublicKey.h>
9#include <xrpl/protocol/SecretKey.h>
10#include <xrpl/protocol/Seed.h>
11#include <xrpl/protocol/tokens.h>
12
13#include <algorithm>
14#include <cstdint>
15#include <cstring>
16
17namespace xrpl {
18
20{
21 static bool
22 equal(Seed const& lhs, Seed const& rhs)
23 {
24 return std::equal(lhs.data(), lhs.data() + lhs.size(), rhs.data(), rhs.data() + rhs.size());
25 }
26
27public:
28 void
30 {
31 testcase("construction");
32
33 {
34 std::uint8_t src[16];
35
36 for (std::uint8_t i = 0; i < 64; i++)
37 {
38 beast::rngfill(src, sizeof(src), defaultPrng());
39 Seed const seed({src, sizeof(src)});
40 BEAST_EXPECT(memcmp(seed.data(), src, sizeof(src)) == 0);
41 }
42 }
43
44 for (int i = 0; i < 64; i++)
45 {
46 uint128 src;
47 beast::rngfill(src.data(), src.size(), defaultPrng());
48 Seed const seed(src);
49 BEAST_EXPECT(memcmp(seed.data(), src.data(), src.size()) == 0);
50 }
51 }
52
55 {
56 auto const seed1 = generateSeed(passphrase);
57 auto const seed2 = parseBase58<Seed>(toBase58(seed1));
58
59 BEAST_EXPECT(static_cast<bool>(seed2));
60 BEAST_EXPECT(equal(seed1, *seed2)); // NOLINT(bugprone-unchecked-optional-access)
61 return toBase58(seed1);
62 }
63
64 void
66 {
67 testcase("generation from passphrase");
68 BEAST_EXPECT(testPassphrase("masterpassphrase") == "snoPBrXtMeMyMHUVTgbuqAfg1SUTb");
69 BEAST_EXPECT(testPassphrase("Non-Random Passphrase") == "snMKnVku798EnBwUfxeSD8953sLYA");
70 BEAST_EXPECT(
71 testPassphrase("cookies excitement hand public") == "sspUXGrmjQhq6mgc24jiRuevZiwKT");
72 }
73
74 void
76 {
77 testcase("base58 operations");
78
79 // Success:
80 BEAST_EXPECT(parseBase58<Seed>("snoPBrXtMeMyMHUVTgbuqAfg1SUTb"));
81 BEAST_EXPECT(parseBase58<Seed>("snMKnVku798EnBwUfxeSD8953sLYA"));
82 BEAST_EXPECT(parseBase58<Seed>("sspUXGrmjQhq6mgc24jiRuevZiwKT"));
83
84 // Failure:
85 BEAST_EXPECT(!parseBase58<Seed>(""));
86 BEAST_EXPECT(!parseBase58<Seed>("sspUXGrmjQhq6mgc24jiRuevZiwK"));
87 BEAST_EXPECT(!parseBase58<Seed>("sspUXGrmjQhq6mgc24jiRuevZiwKTT"));
88 BEAST_EXPECT(!parseBase58<Seed>("sspOXGrmjQhq6mgc24jiRuevZiwKT"));
89 BEAST_EXPECT(!parseBase58<Seed>("ssp/XGrmjQhq6mgc24jiRuevZiwKT"));
90 }
91
92 void
94 {
95 testcase("random generation");
96
97 for (int i = 0; i < 32; i++)
98 {
99 auto const seed1 = randomSeed();
100 auto const seed2 = parseBase58<Seed>(toBase58(seed1));
101
102 BEAST_EXPECT(static_cast<bool>(seed2));
103 BEAST_EXPECT(equal(seed1, *seed2)); // NOLINT(bugprone-unchecked-optional-access)
104 }
105 }
106
107 void
109 {
110 std::string const message1 = "http://www.xrpl.org";
111 std::string const message2 = "https://www.xrpl.org";
112
113 {
114 testcase("Node keypair generation & signing (secp256k1)");
115
116 auto const secretKey =
118 auto const publicKey = derivePublicKey(KeyType::Secp256k1, secretKey);
119
120 BEAST_EXPECT(
121 toBase58(TokenType::NodePublic, publicKey) ==
122 "n94a1u4jAz288pZLtw6yFWVbi89YamiC6JBXPVUj5zmExe5fTVg9");
123 BEAST_EXPECT(
124 toBase58(TokenType::NodePrivate, secretKey) ==
125 "pnen77YEeUd4fFKG7iycBWcwKpTaeFRkW2WFostaATy1DSupwXe");
126 BEAST_EXPECT(
127 to_string(calcNodeID(publicKey)) == "7E59C17D50F5959C7B158FEC95C8F815BF653DC8");
128
129 auto sig = sign(publicKey, secretKey, makeSlice(message1));
130 BEAST_EXPECT(!sig.empty());
131 BEAST_EXPECT(verify(publicKey, makeSlice(message1), sig));
132
133 // Correct public key but wrong message
134 BEAST_EXPECT(!verify(publicKey, makeSlice(message2), sig));
135
136 // Verify with incorrect public key
137 {
138 auto const otherPublicKey = derivePublicKey(
141
142 BEAST_EXPECT(!verify(otherPublicKey, makeSlice(message1), sig));
143 }
144
145 // Correct public key but wrong signature
146 {
147 // Slightly change the signature:
148 if (auto ptr = sig.data())
149 ptr[sig.size() / 2]++;
150
151 BEAST_EXPECT(!verify(publicKey, makeSlice(message1), sig));
152 }
153 }
154
155 {
156 testcase("Node keypair generation & signing (ed25519)");
157
158 auto const secretKey =
159 generateSecretKey(KeyType::Ed25519, generateSeed("masterpassphrase"));
160 auto const publicKey = derivePublicKey(KeyType::Ed25519, secretKey);
161
162 BEAST_EXPECT(
163 toBase58(TokenType::NodePublic, publicKey) ==
164 "nHUeeJCSY2dM71oxM8Cgjouf5ekTuev2mwDpc374aLMxzDLXNmjf");
165 BEAST_EXPECT(
166 toBase58(TokenType::NodePrivate, secretKey) ==
167 "paKv46LztLqK3GaKz1rG2nQGN6M4JLyRtxFBYFTw4wAVHtGys36");
168 BEAST_EXPECT(
169 to_string(calcNodeID(publicKey)) == "AA066C988C712815CC37AF71472B7CBBBD4E2A0A");
170
171 auto sig = sign(publicKey, secretKey, makeSlice(message1));
172 BEAST_EXPECT(!sig.empty());
173 BEAST_EXPECT(verify(publicKey, makeSlice(message1), sig));
174
175 // Correct public key but wrong message
176 BEAST_EXPECT(!verify(publicKey, makeSlice(message2), sig));
177
178 // Verify with incorrect public key
179 {
180 auto const otherPublicKey = derivePublicKey(
182 generateSecretKey(KeyType::Ed25519, generateSeed("otherpassphrase")));
183
184 BEAST_EXPECT(!verify(otherPublicKey, makeSlice(message1), sig));
185 }
186
187 // Correct public key but wrong signature
188 {
189 // Slightly change the signature:
190 if (auto ptr = sig.data())
191 ptr[sig.size() / 2]++;
192
193 BEAST_EXPECT(!verify(publicKey, makeSlice(message1), sig));
194 }
195 }
196
197 {
198 testcase("Account keypair generation & signing (secp256k1)");
199
200 auto const [pk, sk] =
201 generateKeyPair(KeyType::Secp256k1, generateSeed("masterpassphrase"));
202
203 BEAST_EXPECT(toBase58(calcAccountID(pk)) == "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
204 BEAST_EXPECT(
206 "aBQG8RQAzjs1eTKFEAQXr2gS4utcDiEC9wmi7pfUPTi27VCahwgw");
207 BEAST_EXPECT(
209 "p9JfM6HHi64m6mvB6v5k7G2b1cXzGmYiCNJf6GHPKvFTWdeRVjh");
210
211 auto sig = sign(pk, sk, makeSlice(message1));
212 BEAST_EXPECT(!sig.empty());
213 BEAST_EXPECT(verify(pk, makeSlice(message1), sig));
214
215 // Correct public key but wrong message
216 BEAST_EXPECT(!verify(pk, makeSlice(message2), sig));
217
218 // Verify with incorrect public key
219 {
220 auto const otherKeyPair =
222
223 BEAST_EXPECT(!verify(otherKeyPair.first, makeSlice(message1), sig));
224 }
225
226 // Correct public key but wrong signature
227 {
228 // Slightly change the signature:
229 if (auto ptr = sig.data())
230 ptr[sig.size() / 2]++;
231
232 BEAST_EXPECT(!verify(pk, makeSlice(message1), sig));
233 }
234 }
235
236 {
237 testcase("Account keypair generation & signing (ed25519)");
238
239 auto const [pk, sk] =
240 generateKeyPair(KeyType::Ed25519, generateSeed("masterpassphrase"));
241
242 BEAST_EXPECT(to_string(calcAccountID(pk)) == "rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf");
243 BEAST_EXPECT(
245 "aKGheSBjmCsKJVuLNKRAKpZXT6wpk2FCuEZAXJupXgdAxX5THCqR");
246 BEAST_EXPECT(
248 "pwDQjwEhbUBmPuEjFpEG75bFhv2obkCB7NxQsfFxM7xGHBMVPu9");
249
250 auto sig = sign(pk, sk, makeSlice(message1));
251 BEAST_EXPECT(!sig.empty());
252 BEAST_EXPECT(verify(pk, makeSlice(message1), sig));
253
254 // Correct public key but wrong message
255 BEAST_EXPECT(!verify(pk, makeSlice(message2), sig));
256
257 // Verify with incorrect public key
258 {
259 auto const otherKeyPair =
260 generateKeyPair(KeyType::Ed25519, generateSeed("otherpassphrase"));
261
262 BEAST_EXPECT(!verify(otherKeyPair.first, makeSlice(message1), sig));
263 }
264
265 // Correct public key but wrong signature
266 {
267 // Slightly change the signature:
268 if (auto ptr = sig.data())
269 ptr[sig.size() / 2]++;
270
271 BEAST_EXPECT(!verify(pk, makeSlice(message1), sig));
272 }
273 }
274 }
275
276 void
278 {
279 testcase("Parsing");
280
281 // account IDs and node and account public and private
282 // keys should not be parsable as seeds.
283
284 auto const node1 = randomKeyPair(KeyType::Secp256k1);
285
286 BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::NodePublic, node1.first)));
287 BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::NodePrivate, node1.second)));
288
289 auto const node2 = randomKeyPair(KeyType::Ed25519);
290
291 BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::NodePublic, node2.first)));
292 BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::NodePrivate, node2.second)));
293
294 auto const account1 = generateKeyPair(KeyType::Secp256k1, randomSeed());
295
296 BEAST_EXPECT(!parseGenericSeed(toBase58(calcAccountID(account1.first))));
297 BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::AccountPublic, account1.first)));
298 BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::AccountSecret, account1.second)));
299
300 auto const account2 = generateKeyPair(KeyType::Ed25519, randomSeed());
301
302 BEAST_EXPECT(!parseGenericSeed(toBase58(calcAccountID(account2.first))));
303 BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::AccountPublic, account2.first)));
304 BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::AccountSecret, account2.second)));
305 }
306
307 void
308 run() override
309 {
312 testBase58();
313 testRandom();
316 }
317};
318
320
321} // namespace xrpl
A testsuite class.
Definition suite.h:50
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:149
pointer data()
Definition base_uint.h:106
static constexpr std::size_t size()
Definition base_uint.h:530
void testSeedParsing()
void testKeypairGenerationAndSigning()
std::string testPassphrase(std::string passphrase)
Definition Seed_test.cpp:54
static bool equal(Seed const &lhs, Seed const &rhs)
Definition Seed_test.cpp:22
void run() override
Runs the suite.
void testPassphrase()
Definition Seed_test.cpp:65
void testConstruction()
Definition Seed_test.cpp:29
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
T equal(T... args)
void rngfill(void *const buffer, std::size_t const bytes, Generator &g)
Definition rngfill.h:14
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
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.
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
Seed randomSeed()
Create a seed using secure random numbers.
Definition Seed.cpp:48
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig) noexcept
Verify a signature on a message.
BaseUInt< 128 > uint128
Definition base_uint.h:560
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:93
SecretKey generateSecretKey(KeyType type, Seed const &seed)
Generate a new secret key deterministically.
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
Definition Seed.cpp:58
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
AccountID calcAccountID(PublicKey const &pk)
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &message)
Generate a signature for a message.
beast::xor_shift_engine & defaultPrng()
Return the default random engine.
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, xrpl)
std::optional< Seed > parseGenericSeed(std::string const &str, bool rfc1751=true)
Attempt to parse a string as a seed.
Definition Seed.cpp:79
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