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