diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj
index fabbe4379b..deec70bf10 100644
--- a/Builds/VisualStudio2013/RippleD.vcxproj
+++ b/Builds/VisualStudio2013/RippleD.vcxproj
@@ -2705,6 +2705,8 @@
True
+
+
True
@@ -2743,6 +2745,11 @@
+
+ True
+
+
+
True
@@ -2814,6 +2821,9 @@
True
+
+ True
+
True
diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters
index 5641b4aed3..9f89b82bda 100644
--- a/Builds/VisualStudio2013/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters
@@ -3762,6 +3762,9 @@
ripple\rpc\handlers
+
+ ripple\rpc\handlers
+
ripple\rpc\handlers
@@ -3807,6 +3810,12 @@
ripple\rpc\impl
+
+ ripple\rpc\impl
+
+
+ ripple\rpc\impl
+
ripple\rpc\impl
@@ -3891,6 +3900,9 @@
ripple\rpc\tests
+
+ ripple\rpc\tests
+
ripple\rpc\tests
diff --git a/src/ripple/rpc/handlers/WalletPropose.cpp b/src/ripple/rpc/handlers/WalletPropose.cpp
index a60063c574..586e0797d2 100644
--- a/src/ripple/rpc/handlers/WalletPropose.cpp
+++ b/src/ripple/rpc/handlers/WalletPropose.cpp
@@ -18,6 +18,7 @@
//==============================================================================
#include
+#include
namespace ripple {
@@ -25,14 +26,19 @@ namespace ripple {
// passphrase:
// }
Json::Value doWalletPropose (RPC::Context& context)
+{
+ return walletPropose (context.params);
+}
+
+Json::Value walletPropose (Json::Value const& params)
{
RippleAddress naSeed;
RippleAddress naAccount;
- if (!context.params.isMember ("passphrase"))
+ if (!params.isMember ("passphrase"))
naSeed.setSeedRandom ();
- else if (!naSeed.setSeedGeneric (context.params["passphrase"].asString ()))
+ else if (!naSeed.setSeedGeneric (params["passphrase"].asString ()))
return rpcError(rpcBAD_SEED);
RippleAddress naGenerator = RippleAddress::createGeneratorPublic (naSeed);
diff --git a/src/ripple/rpc/handlers/WalletPropose.h b/src/ripple/rpc/handlers/WalletPropose.h
new file mode 100644
index 0000000000..b53042cb33
--- /dev/null
+++ b/src/ripple/rpc/handlers/WalletPropose.h
@@ -0,0 +1,31 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2015 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef RIPPLED_RIPPLE_RPC_HANDLERS_WALLETPROPOSE_H
+#define RIPPLED_RIPPLE_RPC_HANDLERS_WALLETPROPOSE_H
+
+#include
+
+namespace ripple {
+
+Json::Value walletPropose (Json::Value const& params);
+
+} // ripple
+
+#endif
diff --git a/src/ripple/rpc/impl/KeypairForSignature.cpp b/src/ripple/rpc/impl/KeypairForSignature.cpp
new file mode 100644
index 0000000000..16b9cd714f
--- /dev/null
+++ b/src/ripple/rpc/impl/KeypairForSignature.cpp
@@ -0,0 +1,55 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2012-2015 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#include
+#include
+
+namespace ripple {
+namespace RPC {
+
+KeyPair keypairForSignature (Json::Value const& params, Json::Value& error)
+{
+ if (! params.isMember ("secret"))
+ {
+ error = RPC::missing_field_error ("secret");
+
+ return KeyPair();
+ }
+
+ RippleAddress seed;
+
+ if (! seed.setSeedGeneric (params["secret"].asString ()))
+ {
+ error = RPC::make_error (rpcBAD_SEED,
+ RPC::invalid_field_message ("secret"));
+
+ return KeyPair();
+ }
+
+ KeyPair result;
+
+ RippleAddress generator = RippleAddress::createGeneratorPublic (seed);
+ result.secretKey.setAccountPrivate (generator, seed, 0);
+ result.publicKey.setAccountPublic (generator, 0);
+
+ return result;
+}
+
+} // RPC
+} // ripple
diff --git a/src/ripple/rpc/impl/KeypairForSignature.h b/src/ripple/rpc/impl/KeypairForSignature.h
new file mode 100644
index 0000000000..66e84c82f4
--- /dev/null
+++ b/src/ripple/rpc/impl/KeypairForSignature.h
@@ -0,0 +1,40 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2015 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef RIPPLE_RPC_SIGNATUREKEYPAIR_H_INCLUDED
+#define RIPPLE_RPC_SIGNATUREKEYPAIR_H_INCLUDED
+
+#include
+#include
+
+namespace ripple {
+namespace RPC {
+
+struct KeyPair
+{
+ RippleAddress secretKey;
+ RippleAddress publicKey;
+};
+
+KeyPair keypairForSignature (Json::Value const& params, Json::Value& error);
+
+} // RPC
+} // ripple
+
+#endif
diff --git a/src/ripple/rpc/impl/TransactionSign.cpp b/src/ripple/rpc/impl/TransactionSign.cpp
index 6144d9863b..e6a1a5480c 100644
--- a/src/ripple/rpc/impl/TransactionSign.cpp
+++ b/src/ripple/rpc/impl/TransactionSign.cpp
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include
#include
@@ -335,18 +336,16 @@ transactionSign (
WriteLog (lsDEBUG, RPCHandler) << "transactionSign: " << params;
- if (! params.isMember ("secret"))
- return RPC::missing_field_error ("secret");
+ KeyPair const keypair = keypairForSignature (params, jvResult);
+
+ if (contains_error (jvResult))
+ {
+ return jvResult;
+ }
if (! params.isMember ("tx_json"))
return RPC::missing_field_error ("tx_json");
- RippleAddress naSeed;
-
- if (! naSeed.setSeedGeneric (params["secret"].asString ()))
- return RPC::make_error (rpcBAD_SEED,
- RPC::invalid_field_message ("secret"));
-
Json::Value& tx_json (params ["tx_json"]);
if (! tx_json.isObject ())
@@ -426,20 +425,13 @@ transactionSign (
return rpcError (rpcSRC_ACT_NOT_FOUND);
}
- RippleAddress secret = RippleAddress::createSeedGeneric (
- params["secret"].asString ());
- RippleAddress masterGenerator = RippleAddress::createGeneratorPublic (
- secret);
- RippleAddress masterAccountPublic = RippleAddress::createAccountPublic (
- masterGenerator, 0);
-
if (verify)
{
WriteLog (lsTRACE, RPCHandler) <<
- "verify: " << masterAccountPublic.humanAccountID () <<
+ "verify: " << keypair.publicKey.humanAccountID() <<
" : " << raSrcAddressID.humanAccountID ();
- auto const secretAccountID = masterAccountPublic.getAccountID();
+ auto const secretAccountID = keypair.publicKey.getAccountID();
if (raSrcAddressID.getAccountID () == secretAccountID)
{
if (ledgerFacade.accountMasterDisabled ())
@@ -462,7 +454,7 @@ transactionSign (
std::unique_ptr sopTrans = std::move(parsed.object);
sopTrans->setFieldVL (
sfSigningPubKey,
- masterAccountPublic.getAccountPublic ());
+ keypair.publicKey.getAccountPublic());
STTx::pointer stpTrans;
@@ -489,10 +481,8 @@ transactionSign (
// FIXME: For performance, transactions should not be signed in this code
// path.
- RippleAddress naAccountPrivate = RippleAddress::createAccountPrivate (
- masterGenerator, secret, 0);
- stpTrans->sign (naAccountPrivate);
+ stpTrans->sign (keypair.secretKey);
Transaction::pointer tpTrans;
diff --git a/src/ripple/rpc/tests/KeyGeneration.test.cpp b/src/ripple/rpc/tests/KeyGeneration.test.cpp
new file mode 100644
index 0000000000..81e7d15891
--- /dev/null
+++ b/src/ripple/rpc/tests/KeyGeneration.test.cpp
@@ -0,0 +1,178 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2015 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#include
+#include
+#include
+#include
+#include
+
+namespace ripple {
+
+namespace RPC {
+
+struct key_strings
+{
+ char const* account_id;
+ char const* master_key;
+ char const* master_seed;
+ char const* master_seed_hex;
+ char const* public_key;
+ char const* public_key_hex;
+ char const* secret_key_hex;
+};
+
+namespace common {
+static char const* passphrase = "REINDEER FLOTILLA";
+static char const* master_key = "SCAT BERN ISLE FOR ROIL BUS SOAK AQUA FREE FOR DRAM BRIG";
+static char const* master_seed = "snMwVWs2hZzfDUF3p2tHZ3EgmyhFs";
+static char const* master_seed_hex = "BE6A670A19B209E112146D0A7ED2AAD7";
+}
+
+static key_strings const secp256k1_strings =
+{
+ "r4Vtj2jrfmTVZGfSP3gH9hQPMqFPQFin8f",
+ common::master_key,
+ common::master_seed,
+ common::master_seed_hex,
+ "aBQxK2YFNqzmAaXNczYcjqDjfiKkLsJUizsr1UBf44RCF8FHdrmX",
+ "038AAE247B2344B1837FBED8F57389C8C11774510A3F7D784F2A09F0CB6843236C",
+ "1949ECD889EA71324BC7A30C8E81F4E93CB73EE19D59E9082111E78CC3DDABC2",
+};
+
+class WalletPropose_test : public ripple::TestSuite
+{
+public:
+ void testRandomWallet()
+ {
+ Json::Value params;
+ Json::Value result = walletPropose (params);
+
+ expect (! contains_error (result));
+ expect (result.isMember ("account_id"));
+ expect (result.isMember ("master_key"));
+ expect (result.isMember ("master_seed"));
+ expect (result.isMember ("master_seed_hex"));
+ expect (result.isMember ("public_key"));
+ expect (result.isMember ("public_key_hex"));
+
+ std::string seed = result["master_seed"].asString();
+
+ result = walletPropose (params);
+
+ // We asked for two random seeds, so they shouldn't match.
+ expect (result["master_seed"].asString() != seed, seed);
+ }
+
+ void testSecretWallet (Json::Value const& params, key_strings const& s)
+ {
+ Json::Value result = walletPropose (params);
+
+ expect (! contains_error (result));
+ expectEquals (result["account_id"], s.account_id);
+ expectEquals (result["master_key"], s.master_key);
+ expectEquals (result["master_seed"], s.master_seed);
+ expectEquals (result["master_seed_hex"], s.master_seed_hex);
+ expectEquals (result["public_key"], s.public_key);
+ expectEquals (result["public_key_hex"], s.public_key_hex);
+ }
+
+ void testLegacyPassphrase (char const* value)
+ {
+ testcase (value);
+
+ Json::Value params;
+ params["passphrase"] = value;
+
+ testSecretWallet (params, secp256k1_strings);
+ }
+
+ void testLegacyPassphrase()
+ {
+ testLegacyPassphrase (common::passphrase);
+ testLegacyPassphrase (secp256k1_strings.master_key);
+ testLegacyPassphrase (secp256k1_strings.master_seed);
+ testLegacyPassphrase (secp256k1_strings.master_seed_hex);
+ }
+
+ void run()
+ {
+ testRandomWallet();
+ testLegacyPassphrase();
+ }
+};
+
+class KeypairForSignature_test : public ripple::TestSuite
+{
+public:
+ void testEmpty()
+ {
+ Json::Value params;
+ Json::Value error;
+
+ (void) keypairForSignature (params, error);
+
+ expect (contains_error (error) );
+ }
+
+ void testSecretWallet (Json::Value const& params, key_strings const& s)
+ {
+ Json::Value error;
+ KeyPair keypair = keypairForSignature (params, error);
+
+ uint256 secret_key = keypair.secretKey.getAccountPrivate();
+ Blob public_key = keypair.publicKey.getAccountPublic();
+
+ std::string secret_key_hex = strHex (secret_key.data(), secret_key.size());
+ std::string public_key_hex = strHex (public_key.data(), public_key.size());
+
+ expectEquals (secret_key_hex, s.secret_key_hex);
+ expectEquals (public_key_hex, s.public_key_hex);
+ }
+
+ void testLegacySecret (char const* value)
+ {
+ testcase (value);
+
+ Json::Value params;
+ params["secret"] = value;
+
+ testSecretWallet (params, secp256k1_strings);
+ }
+
+ void testLegacySecret()
+ {
+ testLegacySecret (common::passphrase);
+ testLegacySecret (secp256k1_strings.master_key);
+ testLegacySecret (secp256k1_strings.master_seed);
+ testLegacySecret (secp256k1_strings.master_seed_hex);
+ }
+
+ void run()
+ {
+ testEmpty();
+ testLegacySecret();
+ }
+};
+
+BEAST_DEFINE_TESTSUITE(WalletPropose,ripple_basics,ripple);
+BEAST_DEFINE_TESTSUITE(KeypairForSignature,ripple_basics,ripple);
+
+} // RPC
+} // ripple
diff --git a/src/ripple/unity/rpcx.cpp b/src/ripple/unity/rpcx.cpp
index 027cbd6746..f2bb86abc7 100644
--- a/src/ripple/unity/rpcx.cpp
+++ b/src/ripple/unity/rpcx.cpp
@@ -99,6 +99,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -109,6 +110,7 @@
#include
#include
#include
+#include
#include
#include
#include