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

View file

@ -77,6 +77,15 @@ namespace std
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
@ -85,6 +94,7 @@ struct blackball_state_t
std::unordered_map<output_data, std::unordered_set<crypto::key_image>> outputs;
std::unordered_map<std::string, uint64_t> processed_heights;
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)
{
@ -92,9 +102,12 @@ struct blackball_state_t
a & outputs;
a & processed_heights;
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()
{
@ -181,6 +194,24 @@ static bool for_all_transactions(const std::string &filename, uint64_t &start_id
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[])
{
TRY_ENTRY();
@ -396,15 +427,27 @@ int main(int argc, char* argv[])
for (uint64_t out: absolute)
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();
state.ring_instances[new_ring] += 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");
ringdb.blackball(pkey);
newly_spent.insert(output_data(txin.amount, txin.key_offsets[0]));
state.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, 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())
{