blockchain_blackball: also blackball N N-sized duplicate rings

These are unlikely to happen at random, but Wijaya et al made
a paper about it, so people might try it on purpose now (and it
turns out it's easy to add anyway)
This commit is contained in:
moneromooo-monero 2018-04-19 09:36:31 +01:00
parent 66f4700f57
commit e09710f76e
No known key found for this signature in database
GPG Key ID: 686F07454D6CEFC3
1 changed files with 48 additions and 5 deletions

View File

@ -77,6 +77,15 @@ namespace std
return reinterpret_cast<const std::size_t &>(h); return reinterpret_cast<const std::size_t &>(h);
} }
}; };
template<> struct hash<std::vector<uint64_t>>
{
size_t operator()(const std::vector<uint64_t> &v) const
{
crypto::hash h;
crypto::cn_fast_hash(v.data(), v.size() * sizeof(uint64_t), h);
return reinterpret_cast<const std::size_t &>(h);
}
};
} }
struct blackball_state_t struct blackball_state_t
@ -85,6 +94,7 @@ struct blackball_state_t
std::unordered_map<output_data, std::unordered_set<crypto::key_image>> outputs; std::unordered_map<output_data, std::unordered_set<crypto::key_image>> outputs;
std::unordered_map<std::string, uint64_t> processed_heights; std::unordered_map<std::string, uint64_t> processed_heights;
std::unordered_set<output_data> spent; std::unordered_set<output_data> spent;
std::unordered_map<std::vector<uint64_t>, size_t> ring_instances;
template <typename t_archive> void serialize(t_archive &a, const unsigned int ver) template <typename t_archive> void serialize(t_archive &a, const unsigned int ver)
{ {
@ -92,9 +102,12 @@ struct blackball_state_t
a & outputs; a & outputs;
a & processed_heights; a & processed_heights;
a & spent; a & spent;
if (ver < 1)
return;
a & ring_instances;
} }
}; };
BOOST_CLASS_VERSION(blackball_state_t, 0) BOOST_CLASS_VERSION(blackball_state_t, 1)
static std::string get_default_db_path() static std::string get_default_db_path()
{ {
@ -181,6 +194,24 @@ static bool for_all_transactions(const std::string &filename, uint64_t &start_id
return fret; return fret;
} }
static std::vector<uint64_t> canonicalize(const std::vector<uint64_t> &v)
{
std::vector<uint64_t> c;
c.reserve(v.size());
c.push_back(v[0]);
for (size_t n = 1; n < v.size(); ++n)
{
if (v[n] != 0)
c.push_back(v[n]);
}
if (c.size() < v.size())
{
MINFO("Ring has duplicate member(s): " <<
boost::join(v | boost::adaptors::transformed([](uint64_t out){return std::to_string(out);}), " "));
}
return c;
}
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
TRY_ENTRY(); TRY_ENTRY();
@ -396,15 +427,27 @@ int main(int argc, char* argv[])
for (uint64_t out: absolute) for (uint64_t out: absolute)
state.outputs[output_data(txin.amount, out)].insert(txin.k_image); state.outputs[output_data(txin.amount, out)].insert(txin.k_image);
std::vector<uint64_t> new_ring = txin.key_offsets; std::vector<uint64_t> new_ring = canonicalize(txin.key_offsets);
const uint32_t ring_size = txin.key_offsets.size(); const uint32_t ring_size = txin.key_offsets.size();
state.ring_instances[new_ring] += 1;
if (ring_size == 1) if (ring_size == 1)
{ {
const crypto::public_key pkey = core_storage[n]->get_output_key(txin.amount, txin.key_offsets[0]); const crypto::public_key pkey = core_storage[n]->get_output_key(txin.amount, absolute[0]);
MINFO("Blackballing output " << pkey << ", due to being used in a 1-ring"); MINFO("Blackballing output " << pkey << ", due to being used in a 1-ring");
ringdb.blackball(pkey); ringdb.blackball(pkey);
newly_spent.insert(output_data(txin.amount, txin.key_offsets[0])); newly_spent.insert(output_data(txin.amount, absolute[0]));
state.spent.insert(output_data(txin.amount, txin.key_offsets[0])); state.spent.insert(output_data(txin.amount, absolute[0]));
}
else if (state.ring_instances[new_ring] == new_ring.size())
{
for (size_t o = 0; o < new_ring.size(); ++o)
{
const crypto::public_key pkey = core_storage[n]->get_output_key(txin.amount, absolute[o]);
MINFO("Blackballing output " << pkey << ", due to being used in " << new_ring.size() << " identical " << new_ring.size() << "-rings");
ringdb.blackball(pkey);
newly_spent.insert(output_data(txin.amount, absolute[o]));
state.spent.insert(output_data(txin.amount, absolute[o]));
}
} }
else if (state.relative_rings.find(txin.k_image) != state.relative_rings.end()) else if (state.relative_rings.find(txin.k_image) != state.relative_rings.end())
{ {