Skip to content

Commit

Permalink
wallet: add a set_ring command
Browse files Browse the repository at this point in the history
This is so one can set rings for spent key images in case the
attackers don't merge the ring matching patch set.
  • Loading branch information
moneromooo-monero committed Mar 3, 2018
1 parent cf13187 commit 2b02c65
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 1 deletion.
81 changes: 80 additions & 1 deletion src/simplewallet/simplewallet.cpp
Expand Up @@ -1218,7 +1218,7 @@ bool simple_wallet::print_ring(const std::vector<std::string> &args)
std::stringstream str;
for (const auto &x: ring)
str << std::to_string(x) << " ";
success_msg_writer() << tr("Ring size ") << std::to_string(ring.size()) << ": " << str.str();
success_msg_writer() << tr("Ring size ") << std::to_string(ring.size()) << ": " << str.str() << tr(" (absolute)");
}
else
{
Expand All @@ -1233,6 +1233,81 @@ bool simple_wallet::print_ring(const std::vector<std::string> &args)
return true;
}

bool simple_wallet::set_ring(const std::vector<std::string> &args)
{
crypto::key_image key_image;
if (args.size() < 3)
{
fail_msg_writer() << tr("usage: set_ring <key_image> absolute|relative <index> [<index>...]");
return true;
}

if (!epee::string_tools::hex_to_pod(args[0], key_image))
{
fail_msg_writer() << tr("Invalid key image");
return true;
}

bool relative;
if (args[1] == "absolute")
{
relative = false;
}
else if (args[1] == "relative")
{
relative = true;
}
else
{
fail_msg_writer() << tr("Missing absolute or relative keyword");
return true;
}

std::vector<uint64_t> ring;
for (size_t n = 2; n < args.size(); ++n)
{
ring.resize(ring.size() + 1);
if (!string_tools::get_xtype_from_string(ring.back(), args[n]))
{
fail_msg_writer() << tr("invalid index: must be a strictly positive unsigned integer");
return true;
}
if (relative)
{
if (ring.size() > 1 && !ring.back())
{
fail_msg_writer() << tr("invalid index: must be a strictly positive unsigned integer");
return true;
}
uint64_t sum = 0;
for (uint64_t out: ring)
{
if (out > std::numeric_limits<uint64_t>::max() - sum)
{
fail_msg_writer() << tr("invalid index: indices wrap");
return true;
}
sum += out;
}
}
else
{
if (ring.size() > 1 && ring[ring.size() - 2] >= ring[ring.size() - 1])
{
fail_msg_writer() << tr("invalid index: indices should be in strictly ascending order");
return true;
}
}
}
if (!m_wallet->set_ring(key_image, ring, relative))
{
fail_msg_writer() << tr("failed to set ring");
return true;
}

return true;
}

bool simple_wallet::blackball(const std::vector<std::string> &args)
{
crypto::public_key output;
Expand Down Expand Up @@ -2063,6 +2138,10 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::print_ring, this, _1),
tr("print_ring <key_image>"),
tr("Print the ring used to spend a given key image (if the ring size is > 1)"));
m_cmd_binder.set_handler("set_ring",
boost::bind(&simple_wallet::set_ring, this, _1),
tr("set_ring <key_image> absolute|relative <index> [<index>...]"),
tr("Set the ring used for a given key image, so it can be reused in a fork"));
m_cmd_binder.set_handler("save_known_rings",
boost::bind(&simple_wallet::save_known_rings, this, _1),
tr("save_known_rings"),
Expand Down
1 change: 1 addition & 0 deletions src/simplewallet/simplewallet.h
Expand Up @@ -210,6 +210,7 @@ namespace cryptonote
bool submit_multisig(const std::vector<std::string>& args);
bool export_raw_multisig(const std::vector<std::string>& args);
bool print_ring(const std::vector<std::string>& args);
bool set_ring(const std::vector<std::string>& args);
bool save_known_rings(const std::vector<std::string>& args);
bool blackball(const std::vector<std::string>& args);
bool unblackball(const std::vector<std::string>& args);
Expand Down
30 changes: 30 additions & 0 deletions src/wallet/ringdb.cpp
Expand Up @@ -340,6 +340,36 @@ bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_im
return true;
}

bool ringdb::set_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative)
{
MDB_txn *txn;
int dbr;
bool tx_active = false;

dbr = resize_env(env, filename.c_str(), outs.size() * 64);
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set env map size: " + std::string(mdb_strerror(dbr)));
dbr = mdb_txn_begin(env, NULL, 0, &txn);
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create LMDB transaction: " + std::string(mdb_strerror(dbr)));
epee::misc_utils::auto_scope_leave_caller txn_dtor = epee::misc_utils::create_scope_leave_handler([&](){if (tx_active) mdb_txn_abort(txn);});
tx_active = true;

MDB_val key, data;
std::string key_ciphertext = encrypt(key_image, chacha_key);
key.mv_data = (void*)key_ciphertext.data();
key.mv_size = key_ciphertext.size();
std::string compressed_ring = compress_ring(relative ? outs : cryptonote::absolute_output_offsets_to_relative(outs));
std::string data_ciphertext = encrypt(compressed_ring, key_image, chacha_key);
data.mv_size = data_ciphertext.size();
data.mv_data = (void*)data_ciphertext.c_str();
dbr = mdb_put(txn, dbi_rings, &key, &data, 0);
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set ring for key image in LMDB table: " + std::string(mdb_strerror(dbr)));

dbr = mdb_txn_commit(txn);
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to commit txn setting ring to database: " + std::string(mdb_strerror(dbr)));
tx_active = false;
return true;
}

bool ringdb::blackball_worker(const crypto::public_key &output, int op)
{
MDB_txn *txn;
Expand Down
1 change: 1 addition & 0 deletions src/wallet/ringdb.h
Expand Up @@ -46,6 +46,7 @@ namespace tools
bool add_rings(const crypto::chacha_key &chacha_key, const cryptonote::transaction_prefix &tx);
bool remove_rings(const crypto::chacha_key &chacha_key, const cryptonote::transaction_prefix &tx);
bool get_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, std::vector<uint64_t> &outs);
bool set_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative);

bool blackball(const crypto::public_key &output);
bool unblackball(const crypto::public_key &output);
Expand Down
11 changes: 11 additions & 0 deletions src/wallet/wallet2.cpp
Expand Up @@ -5413,6 +5413,17 @@ bool wallet2::get_ring(const crypto::key_image &key_image, std::vector<uint64_t>
return get_ring(key, key_image, outs);
}

bool wallet2::set_ring(const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative)
{
if (!m_ringdb)
return true;

crypto::chacha_key key;
generate_chacha_key_from_secret_keys(key);

return m_ringdb->set_ring(key, key_image, outs, relative);
}

bool wallet2::find_and_save_rings()
{
if (!m_ringdb)
Expand Down
1 change: 1 addition & 0 deletions src/wallet/wallet2.h
Expand Up @@ -1026,6 +1026,7 @@ namespace tools
void set_ring_database(const std::string &filename);
const std::string get_ring_database() const { return m_ring_database; }
bool get_ring(const crypto::key_image &key_image, std::vector<uint64_t> &outs);
bool set_ring(const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative);
bool find_and_save_rings();

bool blackball_output(const crypto::public_key &output);
Expand Down

0 comments on commit 2b02c65

Please sign in to comment.