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 xrpl {
11
13{
14 static bool
15 equal(Seed const& lhs, Seed const& rhs)
16 {
17 return std::equal(lhs.data(), lhs.data() + lhs.size(), rhs.data(), rhs.data() + rhs.size());
18 }
19
20public:
21 void
23 {
24 testcase("construction");
25
26 {
27 std::uint8_t src[16];
28
29 for (std::uint8_t i = 0; i < 64; i++)
30 {
31 beast::rngfill(src, sizeof(src), default_prng());
32 Seed const seed({src, sizeof(src)});
33 BEAST_EXPECT(memcmp(seed.data(), src, sizeof(src)) == 0);
34 }
35 }
36
37 for (int i = 0; i < 64; i++)
38 {
39 uint128 src;
40 beast::rngfill(src.data(), src.size(), default_prng());
41 Seed const seed(src);
42 BEAST_EXPECT(memcmp(seed.data(), src.data(), src.size()) == 0);
43 }
44 }
45
48 {
49 auto const seed1 = generateSeed(passphrase);
50 auto const seed2 = parseBase58<Seed>(toBase58(seed1));
51
52 BEAST_EXPECT(static_cast<bool>(seed2));
53 BEAST_EXPECT(equal(seed1, *seed2));
54 return toBase58(seed1);
55 }
56
57 void
59 {
60 testcase("generation from passphrase");
61 BEAST_EXPECT(testPassphrase("masterpassphrase") == "snoPBrXtMeMyMHUVTgbuqAfg1SUTb");
62 BEAST_EXPECT(testPassphrase("Non-Random Passphrase") == "snMKnVku798EnBwUfxeSD8953sLYA");
63 BEAST_EXPECT(testPassphrase("cookies excitement hand public") == "sspUXGrmjQhq6mgc24jiRuevZiwKT");
64 }
65
66 void
68 {
69 testcase("base58 operations");
70
71 // Success:
72 BEAST_EXPECT(parseBase58<Seed>("snoPBrXtMeMyMHUVTgbuqAfg1SUTb"));
73 BEAST_EXPECT(parseBase58<Seed>("snMKnVku798EnBwUfxeSD8953sLYA"));
74 BEAST_EXPECT(parseBase58<Seed>("sspUXGrmjQhq6mgc24jiRuevZiwKT"));
75
76 // Failure:
77 BEAST_EXPECT(!parseBase58<Seed>(""));
78 BEAST_EXPECT(!parseBase58<Seed>("sspUXGrmjQhq6mgc24jiRuevZiwK"));
79 BEAST_EXPECT(!parseBase58<Seed>("sspUXGrmjQhq6mgc24jiRuevZiwKTT"));
80 BEAST_EXPECT(!parseBase58<Seed>("sspOXGrmjQhq6mgc24jiRuevZiwKT"));
81 BEAST_EXPECT(!parseBase58<Seed>("ssp/XGrmjQhq6mgc24jiRuevZiwKT"));
82 }
83
84 void
86 {
87 testcase("random generation");
88
89 for (int i = 0; i < 32; i++)
90 {
91 auto const seed1 = randomSeed();
92 auto const seed2 = parseBase58<Seed>(toBase58(seed1));
93
94 BEAST_EXPECT(static_cast<bool>(seed2));
95 BEAST_EXPECT(equal(seed1, *seed2));
96 }
97 }
98
99 void
101 {
102 std::string const message1 = "http://www.ripple.com";
103 std::string const message2 = "https://www.ripple.com";
104
105 {
106 testcase("Node keypair generation & signing (secp256k1)");
107
108 auto const secretKey = generateSecretKey(KeyType::secp256k1, generateSeed("masterpassphrase"));
109 auto const publicKey = derivePublicKey(KeyType::secp256k1, secretKey);
110
111 BEAST_EXPECT(
112 toBase58(TokenType::NodePublic, publicKey) == "n94a1u4jAz288pZLtw6yFWVbi89YamiC6JBXPVUj5zmExe5fTVg9");
113 BEAST_EXPECT(
114 toBase58(TokenType::NodePrivate, secretKey) == "pnen77YEeUd4fFKG7iycBWcwKpTaeFRkW2WFostaATy1DSupwXe");
115 BEAST_EXPECT(to_string(calcNodeID(publicKey)) == "7E59C17D50F5959C7B158FEC95C8F815BF653DC8");
116
117 auto sig = sign(publicKey, secretKey, makeSlice(message1));
118 BEAST_EXPECT(sig.size() != 0);
119 BEAST_EXPECT(verify(publicKey, makeSlice(message1), sig));
120
121 // Correct public key but wrong message
122 BEAST_EXPECT(!verify(publicKey, makeSlice(message2), sig));
123
124 // Verify with incorrect public key
125 {
126 auto const otherPublicKey = derivePublicKey(
128
129 BEAST_EXPECT(!verify(otherPublicKey, makeSlice(message1), sig));
130 }
131
132 // Correct public key but wrong signature
133 {
134 // Slightly change the signature:
135 if (auto ptr = sig.data())
136 ptr[sig.size() / 2]++;
137
138 BEAST_EXPECT(!verify(publicKey, makeSlice(message1), sig));
139 }
140 }
141
142 {
143 testcase("Node keypair generation & signing (ed25519)");
144
145 auto const secretKey = generateSecretKey(KeyType::ed25519, generateSeed("masterpassphrase"));
146 auto const publicKey = derivePublicKey(KeyType::ed25519, secretKey);
147
148 BEAST_EXPECT(
149 toBase58(TokenType::NodePublic, publicKey) == "nHUeeJCSY2dM71oxM8Cgjouf5ekTuev2mwDpc374aLMxzDLXNmjf");
150 BEAST_EXPECT(
151 toBase58(TokenType::NodePrivate, secretKey) == "paKv46LztLqK3GaKz1rG2nQGN6M4JLyRtxFBYFTw4wAVHtGys36");
152 BEAST_EXPECT(to_string(calcNodeID(publicKey)) == "AA066C988C712815CC37AF71472B7CBBBD4E2A0A");
153
154 auto sig = sign(publicKey, secretKey, makeSlice(message1));
155 BEAST_EXPECT(sig.size() != 0);
156 BEAST_EXPECT(verify(publicKey, makeSlice(message1), sig));
157
158 // Correct public key but wrong message
159 BEAST_EXPECT(!verify(publicKey, makeSlice(message2), sig));
160
161 // Verify with incorrect public key
162 {
163 auto const otherPublicKey = derivePublicKey(
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("Account keypair generation & signing (secp256k1)");
181
182 auto const [pk, sk] = generateKeyPair(KeyType::secp256k1, generateSeed("masterpassphrase"));
183
184 BEAST_EXPECT(toBase58(calcAccountID(pk)) == "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
185 BEAST_EXPECT(
186 toBase58(TokenType::AccountPublic, pk) == "aBQG8RQAzjs1eTKFEAQXr2gS4utcDiEC9wmi7pfUPTi27VCahwgw");
187 BEAST_EXPECT(
188 toBase58(TokenType::AccountSecret, sk) == "p9JfM6HHi64m6mvB6v5k7G2b1cXzGmYiCNJf6GHPKvFTWdeRVjh");
189
190 auto sig = sign(pk, sk, makeSlice(message1));
191 BEAST_EXPECT(sig.size() != 0);
192 BEAST_EXPECT(verify(pk, makeSlice(message1), sig));
193
194 // Correct public key but wrong message
195 BEAST_EXPECT(!verify(pk, makeSlice(message2), sig));
196
197 // Verify with incorrect public key
198 {
199 auto const otherKeyPair = generateKeyPair(KeyType::secp256k1, generateSeed("otherpassphrase"));
200
201 BEAST_EXPECT(!verify(otherKeyPair.first, makeSlice(message1), sig));
202 }
203
204 // Correct public key but wrong signature
205 {
206 // Slightly change the signature:
207 if (auto ptr = sig.data())
208 ptr[sig.size() / 2]++;
209
210 BEAST_EXPECT(!verify(pk, makeSlice(message1), sig));
211 }
212 }
213
214 {
215 testcase("Account keypair generation & signing (ed25519)");
216
217 auto const [pk, sk] = generateKeyPair(KeyType::ed25519, generateSeed("masterpassphrase"));
218
219 BEAST_EXPECT(to_string(calcAccountID(pk)) == "rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf");
220 BEAST_EXPECT(
221 toBase58(TokenType::AccountPublic, pk) == "aKGheSBjmCsKJVuLNKRAKpZXT6wpk2FCuEZAXJupXgdAxX5THCqR");
222 BEAST_EXPECT(
223 toBase58(TokenType::AccountSecret, sk) == "pwDQjwEhbUBmPuEjFpEG75bFhv2obkCB7NxQsfFxM7xGHBMVPu9");
224
225 auto sig = sign(pk, sk, makeSlice(message1));
226 BEAST_EXPECT(sig.size() != 0);
227 BEAST_EXPECT(verify(pk, makeSlice(message1), sig));
228
229 // Correct public key but wrong message
230 BEAST_EXPECT(!verify(pk, makeSlice(message2), sig));
231
232 // Verify with incorrect public key
233 {
234 auto const otherKeyPair = generateKeyPair(KeyType::ed25519, generateSeed("otherpassphrase"));
235
236 BEAST_EXPECT(!verify(otherKeyPair.first, makeSlice(message1), sig));
237 }
238
239 // Correct public key but wrong signature
240 {
241 // Slightly change the signature:
242 if (auto ptr = sig.data())
243 ptr[sig.size() / 2]++;
244
245 BEAST_EXPECT(!verify(pk, makeSlice(message1), sig));
246 }
247 }
248 }
249
250 void
252 {
253 testcase("Parsing");
254
255 // account IDs and node and account public and private
256 // keys should not be parsable as seeds.
257
258 auto const node1 = randomKeyPair(KeyType::secp256k1);
259
260 BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::NodePublic, node1.first)));
261 BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::NodePrivate, node1.second)));
262
263 auto const node2 = randomKeyPair(KeyType::ed25519);
264
265 BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::NodePublic, node2.first)));
266 BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::NodePrivate, node2.second)));
267
268 auto const account1 = generateKeyPair(KeyType::secp256k1, randomSeed());
269
270 BEAST_EXPECT(!parseGenericSeed(toBase58(calcAccountID(account1.first))));
271 BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::AccountPublic, account1.first)));
272 BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::AccountSecret, account1.second)));
273
274 auto const account2 = generateKeyPair(KeyType::ed25519, randomSeed());
275
276 BEAST_EXPECT(!parseGenericSeed(toBase58(calcAccountID(account2.first))));
277 BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::AccountPublic, account2.first)));
278 BEAST_EXPECT(!parseGenericSeed(toBase58(TokenType::AccountSecret, account2.second)));
279 }
280
281 void
282 run() override
283 {
286 testBase58();
287 testRandom();
290 }
291};
292
293BEAST_DEFINE_TESTSUITE(Seed, protocol, xrpl);
294
295} // namespace xrpl
A testsuite class.
Definition suite.h:52
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:148
void testSeedParsing()
void testKeypairGenerationAndSigning()
std::string testPassphrase(std::string passphrase)
Definition Seed_test.cpp:47
static bool equal(Seed const &lhs, Seed const &rhs)
Definition Seed_test.cpp:15
void run() override
Runs the suite.
void testPassphrase()
Definition Seed_test.cpp:58
void testConstruction()
Definition Seed_test.cpp:22
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
pointer data()
Definition base_uint.h:102
static constexpr std::size_t size()
Definition base_uint.h:495
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::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.
Seed randomSeed()
Create a seed using secure random numbers.
Definition Seed.cpp:47
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:598
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig) noexcept
Verify a signature on a message.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:92
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:57
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
beast::xor_shift_engine & default_prng()
Return the default random engine.
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.
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::optional< Seed > parseGenericSeed(std::string const &str, bool rfc1751=true)
Attempt to parse a string as a seed.
Definition Seed.cpp:78