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/beast/unit_test.h>
22 #include <ripple/beast/utility/rngfill.h>
23 #include <ripple/beast/xor_shift_engine.h>
24 #include <ripple/protocol/PublicKey.h>
25 #include <ripple/protocol/SecretKey.h>
26 #include <ripple/protocol/Seed.h>
27 #include <algorithm>
28 
29 namespace ripple {
30 
31 class Seed_test : public beast::unit_test::suite
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 
43 public:
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(
272  to_string(calcAccountID(pk)) ==
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  {
353  testPassphrase();
354  testBase58();
355  testRandom();
357  testSeedParsing();
358  }
359 };
360 
362 
363 } // namespace 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:241
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:303
ripple::verify
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical) noexcept
Verify a signature on a message.
Definition: PublicKey.cpp:272
ripple::Seed_test::run
void run() override
Definition: Seed_test.cpp:350
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:104
ripple::Seed_test::testKeypairGenerationAndSigning
void testKeypairGenerationAndSigning()
Definition: Seed_test.cpp:129
ripple::base_uint::data
pointer data()
Definition: base_uint.h:122
algorithm
ripple::generateKeyPair
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
Definition: SecretKey.cpp:351
ripple::Seed_test::testPassphrase
void testPassphrase()
Definition: Seed_test.cpp:81
ripple::Seed_test::testSeedParsing
void testSeedParsing()
Definition: Seed_test.cpp:309
ripple::base_uint::size
constexpr static std::size_t size()
Definition: base_uint.h:519
ripple::KeyType::ed25519
@ ed25519
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:82
ripple::Seed_test::testBase58
void testBase58()
Definition: Seed_test.cpp:96
ripple::Seed_test
Definition: Seed_test.cpp:31
ripple::derivePublicKey
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Definition: SecretKey.cpp:313
ripple::calcAccountID
AccountID calcAccountID(PublicKey const &pk)
Definition: AccountID.cpp:158
ripple::randomSeed
Seed randomSeed()
Create a seed using secure random numbers.
Definition: Seed.cpp:59
ripple::default_prng
beast::xor_shift_engine & default_prng()
Return the default random engine.
Definition: ripple/basics/random.h:65
ripple::generateSecretKey
SecretKey generateSecretKey(KeyType type, Seed const &seed)
Generate a new secret key deterministically.
Definition: SecretKey.cpp:291
std::uint8_t
ripple::parseGenericSeed
std::optional< Seed > parseGenericSeed(std::string const &str, bool rfc1751)
Attempt to parse a string as a seed.
Definition: Seed.cpp:90
ripple::KeyType::secp256k1
@ secp256k1
ripple::randomKeyPair
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:368
ripple::generateSeed
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
Definition: Seed.cpp:69
ripple::Seed::size
std::size_t size() const
Definition: Seed.h:64
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
protocol
Definition: ValidatorList.h:38
ripple::sign
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &m)
Generate a signature for a message.
Definition: SecretKey.cpp:238
ripple::TokenType::AccountSecret
@ AccountSecret
beast::rngfill
void rngfill(void *buffer, std::size_t bytes, Generator &g)
Definition: rngfill.h:33
ripple::Seed_test::equal
static bool equal(Seed const &lhs, Seed const &rhs)
Definition: Seed_test.cpp:34
ripple::TokenType::AccountPublic
@ AccountPublic
ripple::TokenType::NodePublic
@ NodePublic
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::Seed_test::testPassphrase
std::string testPassphrase(std::string passphrase)
Definition: Seed_test.cpp:70
ripple::Seed_test::testConstruction
void testConstruction()
Definition: Seed_test.cpp:45
ripple::TokenType::NodePrivate
@ NodePrivate
ripple::Seed::data
std::uint8_t const * data() const
Definition: Seed.h:58
ripple::Seed_test::testRandom
void testRandom()
Definition: Seed_test.cpp:114