Recover Monero address using the private spend key
Monero simplewallet
has a command called spendkey
which prints
out your private spend key. However, its not clear what to do with this private key.
It turns out, that this private key is the hexadecimal representation of the 25 word
mnemonic seed, which simplewallet
gives you when you create a new wallet. For example, the following mnemonic seed:
vinegar talent sorry hybrid ultimate template nimbly jukebox axes inactive veered toenail pride plotting chrome victim agnostic science bailed paddles wounded peaches king laptop king
corresponds to this private spend key:
6ee02ef8647856f4080882a1ec4fabee19ec047ca24d3abb13c0ce589a46f702
Since mnemonic seed always you to restore your deterministic wallet, the same thing can be done with just the private spend key. This includes recovery of your private view key. More on Monero's keys and addresses can be found on Address Generation Tests website.
This example shows how to do this in C++ using Monero libraries.
Monero address
Monero address is as a combination of public spend and view keys. The public keys
are obtained directly from the corresponding private spend and view keys, respectively.
The private view key is obtained from the private spend key (in simplewallet
),
which in turn can be obtained from the mnemonic seed. This means that
spend key is much more important than the view key, since it allows
to recover your private view key (revers is not true). So what it means, is that you should not be disclosing your private spend key to strangers!
Please note that this is not the only way of deriving private keys. For example, MyMonero is using a different procedure, which is not compatible with that in simplewallet
. The procedure presented here is same as the one used in simplewallet
. More on this is
here
and here.
Pre-requisites
Everything here was done and tested on Ubuntu 14.04 x86_64 and Ubuntu 15.10 x86_64.
Monero source code compilation and setup are same as here.
C++ code
The most interesting C++ file is main.cpp
.
Therefore, I will present only that file here. Full source code is
at github. The github's version can
also be slightly different than the code presented here, as it might be updated
more frequently.
So for the latest version
of this example, please check the github repository directly.
main.cpp
This is the main file of the example. The program takes two input arguments:
-
spendkey,s
- the private spend key. -
mnemonic,m
- 25 word mnemonic representation of the spend key.
#include "src/CmdLineOptions.h"
#include "src/tools.h"
#include "mnemonics/electrum-words.h"
using crypto::ElectrumWords::words_to_bytes;
using crypto::ElectrumWords::bytes_to_words;
using xmreg::operator<<;
using namespace std;
unsigned int epee::g_test_dbg_lock_sleep = 0;
int main(int ac, const char* av[]) {
// get command line options
xmreg::CmdLineOptions opts {ac, av};
// if help was chosen, display help text and finish
if (opts.help_requested())
{
return 0;
}
// default language for the mnemonic
// representation of the private spend key
string language {"English"};
// get private spend key options
auto spendkey_opt = opts.get_option<string>("spendkey");
auto mnemonic_opt = opts.get_option<string>("mnemonic");
// get the program command line options, or
// some default values for quick check
string spendkey_str = spendkey_opt ? *spendkey_opt : "af6082af29108abda69cc385dfed2102b892a871695367cb22a4b9b6df8b3206";
string mnemonic_str = mnemonic_opt ? *mnemonic_opt : "spout midst duckling tepid odds glass enhanced avatar ocean rarest eavesdrop egotistic oxygen trying future airport session nanny tedious guru asylum superior cement cunning eavesdrop";
crypto::secret_key private_spend_key;
if ((spendkey_opt && !mnemonic_opt) || (!spendkey_opt && !mnemonic_opt))
{
// if spend key is given or nothing is provided by the user,
// then derive the mnemonic using either key provided or the default one
if (spendkey_opt)
{
// use provided spend key by the user
spendkey_str = *spendkey_opt;
}
// parse string representing given private spend key
if (!xmreg::parse_str_secret_key(spendkey_str, private_spend_key))
{
cerr << "Cant parse the spend key: " << spendkey_str << endl;
return 1;
}
// derive the mnemonic version of the spend key.
// 25 word mnemonic that is provided by the simplewallet
// is just a word representation of the private spend key
if (!bytes_to_words(private_spend_key, mnemonic_str, language))
{
cerr << "\nCant create the mnemonic for the private spend key: "
<< private_spend_key << endl;
return 1;
}
}
else if (!spendkey_opt && mnemonic_opt)
{
// if mnemonic is given, then derive the spend key
if (!words_to_bytes(*mnemonic_opt, private_spend_key, language))
{
cerr << "\nCant create private spend key for the mnemonic: "
<< *mnemonic_opt << endl;
return 1;
}
}
cout << "\n"
<< "Mnemonic: " << mnemonic_str << endl;
// the seed for generation of private view key later on
// is the private spend key.
cout << "\n"
<< "Hexadecimal seed : " << private_spend_key << endl;
cout << "\n"
<< "Private spend key: " << private_spend_key << endl;
// we have private_spend_key, so now
// we need to get the corresponding
// public_spend_key
crypto::public_key public_spend_key;
// generate public key based on the private key
crypto::secret_key_to_public_key(private_spend_key, public_spend_key);
cout << "Public spend key : " << public_spend_key << endl;
// now its time to get the view keys.
// in monero's simplewallet, the private view key
// is generated using keccak hash of the private spend
// key. in other words, the hash of the private spend key
// is used for generating the private view key,
// and subsequently, its corresponding public view key.
crypto::hash hash_of_private_spend_key;
// calculate keccak hash of the private spend key
xmreg::keccak_hash(private_spend_key, hash_of_private_spend_key);
crypto::secret_key private_view_key;
crypto::public_key public_view_key;
// get the view keys using the hash_of_private_spend_key
// as the seed.
crypto::generate_keys(public_view_key, private_view_key,
xmreg::get_key_from_hash<crypto::secret_key>(hash_of_private_spend_key),
true /* recover keys*/);
cout << "\n"
<< "Private view key : " << private_view_key << "\n"
<< "Public view key : " << public_view_key << endl;
// once we have both private view and spend keys, we can get our
// address. Monero's address is a combination of the two
// public keys.
cryptonote::account_public_address address {public_spend_key, public_view_key};
cout << "\n"
<< "Monero address : " << address << endl;
cout << "\n"
<< "End of program." << endl;
return 0;
}
Output example 1
Executing the program as follows:
./spendkey
Results in the following output:
Mnemonic: spout midst duckling tepid odds glass enhanced avatar ocean rarest eavesdrop egotistic oxygen trying future airport session nanny tedious guru asylum superior cement cunning eavesdropspout midst duckling tepid odds glass enhanced avatar ocean rarest eavesdrop egotistic oxygen trying future airport session nanny tedious guru asylum superior cement cunning eavesdrop
Hexadecimal seed : <af6082af29108abda69cc385dfed2102b892a871695367cb22a4b9b6df8b3206>
Private spend key: <af6082af29108abda69cc385dfed2102b892a871695367cb22a4b9b6df8b3206>
Public spend key : <7aff30fbdc005ecb03f57a11e250e0d665621ffde1d44c6aa84a8212cc0d1236>
Private view key : <157874dc4e2961c872f87aaf4346146d0f596e2f116a51fbac01b693a8e3020a>
Public view key : <25c1b6920540fbcfcb0e36bd2c88f5c1e62e5ef1d621279e7230b47648e64a63>
Monero address : <46HSxE7KoiDaxWFWR1wmJfcrunNj4TLiPJqiCJkQn345A4JJzgBNhUvbkrYWJX4EVJZS4kJGfGj7CTW8GEUHsbEZCEupMt6>
These results agree with those obtained using Address Generation Tests website.
Output example 2
Executing the program as follows:
./spendkey -s 11830f8a232b7b0152a709340bb653357d2aa92985f83b6e0dcf7cb2bf11330d
Results in the following output:
Mnemonic: spout midst duckling tepid odds glass enhanced avatar ocean rarest eavesdrop egotistic oxygen trying future airport session nanny tedious guru asylum superior cement cunning eavesdropsiblings together icing idols sovereign sprig suture aloof egotistic speedy diplomat impel wise glass long cafe perfect awakened ought enforce voted mime fight goggles egotistic
Hexadecimal seed : <11830f8a232b7b0152a709340bb653357d2aa92985f83b6e0dcf7cb2bf11330d>
Private spend key: <11830f8a232b7b0152a709340bb653357d2aa92985f83b6e0dcf7cb2bf11330d>
Public spend key : <269e626955fe97f3853d768e0ad02bf92d0a95a8c03704fd8a96d5ad6a38c42a>
Private view key : <21e63fb10d4adad609a327395e42d737bbd772dce53d64d2733c4aacc69eb300>
Public view key : <b4e0cf1d4c7c60b590081db50e877e7576a36fb2c257f5f94932222d23d34b36>
Monero address : <435zP7PmQwYhjTJu7AmU8SigKVMsY9j3yjQfnwnfjRZM89Jp2ZxEpsyXNPKkr5hfwBLeYTiZeqfaLihPNWWEzbgN77gqFHp>
These results also agree with those obtained using Address Generation Tests website.
Output example 3
Executing the program as follows:
./spendkey -m "essential future brunt cajun upper ammo incur smelting usual tyrant tattoo virtual long hectare idols guarded blender usage ghost sample eagle shelter does dozen usage"
Results in the following output:
Mnemonic: essential future brunt cajun upper ammo incur smelting usual tyrant tattoo virtual long hectare idols guarded blender usage ghost sample eagle shelter does dozen usage
Hexadecimal seed : <0a0214cf7716292246d277214830411b20d3cd08cd119dcd9e149d7bd1151e02>
Private spend key: <0a0214cf7716292246d277214830411b20d3cd08cd119dcd9e149d7bd1151e02>
Public spend key : <7e9f73449c1b3a9a83c25a641a95c8f74f7ccd309dd3fba5222ce349052af567>
Private view key : <bd613fbad795df25b8218a7e4f80f4e3158db0646d1cb7d22d84f0b603a0f60b>
Public view key : <fad7d278ee9fedf0034da1812115c5a369d6bd67e1b076afbc4aee579a609ce3>
Monero address : <46RRCV68frZSqzBsh9TWf9iNDrYhPkABUUd16zFLoPECJPjd3AtuTyeh9RhSWAqiCLULKGf9SC1UHWPra64ykRiTSg3RPmW>
These results also agree with those obtained using Address Generation Tests website.
Compile this example
The dependencies are same as those for Monero, so I assume Monero compiles correctly. If so then to download and compile this example, the following steps can be executed:
# download the source code
git clone https://github.com/moneroexamples/spendkey.git
# enter the downloaded sourced code folder
cd spendkey
# create the makefile
cmake .
# compile
make
After this, spendkey
executable file should be present in access-blockchain-in-cpp
folder. How to use it, can be seen in the above example outputs.
How can you help?
Constructive criticism, code and website edits are always good. They can be made through github.
Some Monero are also welcome:
48daf1rG3hE1Txapcsxh6WXNe9MLNKtu7W7tKTivtSoVLHErYzvdcpea2nSTgGkz66RFP4GKVAsTV14v6G3oddBTHfxP6tU