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