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