2015-12-13 14:51:43 +01:00
|
|
|
// Copyright (c) 2012-2015 The Bitcoin Core developers
|
2014-10-31 01:43:19 +01:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
2012-08-13 05:26:27 +02:00
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
2013-04-13 07:13:08 +02:00
|
|
|
|
2012-08-13 05:26:27 +02:00
|
|
|
#ifndef BITCOIN_BLOOM_H
|
|
|
|
#define BITCOIN_BLOOM_H
|
|
|
|
|
2020-03-19 23:46:56 +01:00
|
|
|
#include <serialize.h>
|
2012-08-13 05:26:27 +02:00
|
|
|
|
2013-04-13 07:13:08 +02:00
|
|
|
#include <vector>
|
|
|
|
|
2012-08-13 05:26:27 +02:00
|
|
|
class COutPoint;
|
2019-03-21 21:45:27 +01:00
|
|
|
class CScript;
|
2012-08-13 05:26:27 +02:00
|
|
|
class CTransaction;
|
2013-04-13 07:13:08 +02:00
|
|
|
class uint256;
|
2019-03-21 21:45:27 +01:00
|
|
|
class uint160;
|
2012-08-13 05:26:27 +02:00
|
|
|
|
2014-10-31 01:43:19 +01:00
|
|
|
//! 20,000 items with fp rate < 0.1% or 10,000 items and <0.0001%
|
2012-08-13 05:26:27 +02:00
|
|
|
static const unsigned int MAX_BLOOM_FILTER_SIZE = 36000; // bytes
|
|
|
|
static const unsigned int MAX_HASH_FUNCS = 50;
|
|
|
|
|
2014-10-31 01:43:19 +01:00
|
|
|
/**
|
|
|
|
* First two bits of nFlags control how much IsRelevantAndUpdate actually updates
|
|
|
|
* The remaining bits are reserved
|
|
|
|
*/
|
2013-01-11 02:23:28 +01:00
|
|
|
enum bloomflags
|
|
|
|
{
|
|
|
|
BLOOM_UPDATE_NONE = 0,
|
|
|
|
BLOOM_UPDATE_ALL = 1,
|
|
|
|
// Only adds outpoints to the filter if the output is a pay-to-pubkey/pay-to-multisig script
|
|
|
|
BLOOM_UPDATE_P2PUBKEY_ONLY = 2,
|
|
|
|
BLOOM_UPDATE_MASK = 3,
|
|
|
|
};
|
2012-08-13 05:26:27 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* BloomFilter is a probabilistic filter which SPV clients provide
|
2015-04-28 16:48:28 +02:00
|
|
|
* so that we can filter the transactions we send them.
|
2020-07-29 03:23:12 +02:00
|
|
|
*
|
2012-08-13 05:26:27 +02:00
|
|
|
* This allows for significantly more efficient transaction and block downloads.
|
2020-07-29 03:23:12 +02:00
|
|
|
*
|
2015-04-28 16:48:28 +02:00
|
|
|
* Because bloom filters are probabilistic, a SPV node can increase the false-
|
|
|
|
* positive rate, making us send it transactions which aren't actually its,
|
2012-08-13 05:26:27 +02:00
|
|
|
* allowing clients to trade more bandwidth for more privacy by obfuscating which
|
2015-04-28 16:48:28 +02:00
|
|
|
* keys are controlled by them.
|
2012-08-13 05:26:27 +02:00
|
|
|
*/
|
|
|
|
class CBloomFilter
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
std::vector<unsigned char> vData;
|
|
|
|
unsigned int nHashFuncs;
|
2012-11-02 23:33:50 +01:00
|
|
|
unsigned int nTweak;
|
2013-01-11 02:23:28 +01:00
|
|
|
unsigned char nFlags;
|
2012-08-13 05:26:27 +02:00
|
|
|
|
|
|
|
unsigned int Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const;
|
|
|
|
|
2019-03-21 21:45:27 +01:00
|
|
|
// Check matches for arbitrary script data elements
|
|
|
|
bool CheckScript(const CScript& script) const;
|
|
|
|
// Check additional matches for special transactions
|
|
|
|
bool CheckSpecialTransactionMatchesAndUpdate(const CTransaction& tx);
|
2012-08-13 05:26:27 +02:00
|
|
|
public:
|
2014-10-31 01:43:19 +01:00
|
|
|
/**
|
|
|
|
* Creates a new bloom filter which will provide the given fp rate when filled with the given number of elements
|
|
|
|
* Note that if the given parameters will result in a filter outside the bounds of the protocol limits,
|
|
|
|
* the filter created will be as close to the given parameters as possible within the protocol limits.
|
|
|
|
* This will apply if nFPRate is very low or nElements is unreasonably high.
|
|
|
|
* nTweak is a constant which is added to the seed value passed to the hash function
|
|
|
|
* It should generally always be a random value (and is largely only exposed for unit testing)
|
|
|
|
* nFlags should be one of the BLOOM_UPDATE_* enums (not _MASK)
|
|
|
|
*/
|
2017-05-18 10:08:56 +02:00
|
|
|
CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweak, unsigned char nFlagsIn);
|
Merge #18806: net: remove is{Empty,Full} flags from CBloomFilter, clarify CVE fix
1ad8ea2b73134bdd8d6b50704a019d47ad2191d8 net: remove is{Empty,Full} flags from CBloomFilter, clarify CVE fix (Sebastian Falbesoner)
Pull request description:
The BIP37 bloom filter class `CBloomFilter` contains two flags `isEmpty`/`isFull` together with an update method with the purpose to, according to the comments, "avoid wasting cpu", i.e. the mechanism should serve as an optimization for the trivial cases of empty (all bits zero) or full (all bits one) filters.
However, the real reason of adding those flags (introduced with commit https://github.com/bitcoin/bitcoin/commit/37c6389c5a0ca63ae3573440ecdfe95d28ad8f07 by gmaxwell) was a _covert fix_ of [CVE-2013-5700](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-5700), a vulnerability that allowed a divide-by-zero remote node crash.
According to gmaxwell himself (https://github.com/bitcoin/bitcoin/pull/9060#issuecomment-257749165):
> the IsEmpty/IsFull optimizations were largely a pretextual optimization intended to make unexploitable a remote crash vulnerability (integer division by zero) that existed in the original bloom filtering code without disclosing it. I'm doubtful that they are all that useful. :)
For more information on how to trigger this crash, see PR https://github.com/bitcoin/bitcoin/pull/18515 which contains a detailled description and a regression test. It has also been discussed on a [recent PR club meeting on fuzzing](https://bitcoincore.reviews/18521.html).
The covert fix code already led to issues and PR based on the wrong assumption that the flags are there for optimization reasons (see #16886 and #16922). This PR gets rid of the flags and the update method and just focuses on the CVE fix itself, i.e. it can be seen as a revert of the covert fix commit modulo the actual fix.
ACKs for top commit:
meshcollider:
utACK 1ad8ea2b73134bdd8d6b50704a019d47ad2191d8
laanwj:
Concept and code review ACK 1ad8ea2b73134bdd8d6b50704a019d47ad2191d8
jkczyz:
ACK 1ad8ea2b73134bdd8d6b50704a019d47ad2191d8
MarcoFalke:
ACK 1ad8ea2b73134bdd8d6b50704a019d47ad2191d8
fjahr:
Code review ACK 1ad8ea2b73134bdd8d6b50704a019d47ad2191d8
Tree-SHA512: 29f7ff9faece0285e11e16c024851f5bcb772dec64118ccc3f9067ec256267ec8e1b1e3105c7de2a72fd122c3b085e8fc840ab8f4e49813f1cc7a444df1867f7
2020-05-06 09:06:16 +02:00
|
|
|
CBloomFilter() : nHashFuncs(0), nTweak(0), nFlags(0) {}
|
2012-08-13 05:26:27 +02:00
|
|
|
|
2020-05-20 13:30:21 +02:00
|
|
|
SERIALIZE_METHODS(CBloomFilter, obj) { READWRITE(obj.vData, obj.nHashFuncs, obj.nTweak, obj.nFlags); }
|
2012-08-13 05:26:27 +02:00
|
|
|
|
|
|
|
void insert(const std::vector<unsigned char>& vKey);
|
|
|
|
void insert(const COutPoint& outpoint);
|
|
|
|
void insert(const uint256& hash);
|
|
|
|
|
|
|
|
bool contains(const std::vector<unsigned char>& vKey) const;
|
|
|
|
bool contains(const COutPoint& outpoint) const;
|
|
|
|
bool contains(const uint256& hash) const;
|
2019-03-21 21:45:27 +01:00
|
|
|
bool contains(const uint160& hash) const;
|
2012-08-13 05:26:27 +02:00
|
|
|
|
2014-10-31 01:43:19 +01:00
|
|
|
//! True if the size is <= MAX_BLOOM_FILTER_SIZE and the number of hash functions is <= MAX_HASH_FUNCS
|
|
|
|
//! (catch a filter which was just deserialized which was too big)
|
2012-08-13 05:26:27 +02:00
|
|
|
bool IsWithinSizeConstraints() const;
|
|
|
|
|
2014-10-31 01:43:19 +01:00
|
|
|
//! Also adds any outputs which match the filter to the filter (to match their spending txes)
|
2014-06-09 10:02:00 +02:00
|
|
|
bool IsRelevantAndUpdate(const CTransaction& tx);
|
2012-08-13 05:26:27 +02:00
|
|
|
};
|
|
|
|
|
2015-04-24 19:14:45 +02:00
|
|
|
/**
|
|
|
|
* RollingBloomFilter is a probabilistic "keep track of most recently inserted" set.
|
2015-07-19 21:43:34 +02:00
|
|
|
* Construct it with the number of items to keep track of, and a false-positive
|
|
|
|
* rate. Unlike CBloomFilter, by default nTweak is set to a cryptographically
|
|
|
|
* secure random value for you. Similarly rather than clear() the method
|
|
|
|
* reset() is provided, which also changes nTweak to decrease the impact of
|
|
|
|
* false-positives.
|
2015-04-24 19:14:45 +02:00
|
|
|
*
|
2015-12-03 13:35:55 +01:00
|
|
|
* contains(item) will always return true if item was one of the last N to 1.5*N
|
2015-04-24 19:14:45 +02:00
|
|
|
* insert()'ed ... but may also return true for items that were not inserted.
|
2015-12-03 13:35:55 +01:00
|
|
|
*
|
|
|
|
* It needs around 1.8 bytes per element per factor 0.1 of false positive rate.
|
2020-11-19 11:44:25 +01:00
|
|
|
* For example, if we want 1000 elements, we'd need:
|
|
|
|
* - ~1800 bytes for a false positive rate of 0.1
|
|
|
|
* - ~3600 bytes for a false positive rate of 0.01
|
|
|
|
* - ~5400 bytes for a false positive rate of 0.001
|
|
|
|
*
|
|
|
|
* If we make these simplifying assumptions:
|
|
|
|
* - logFpRate / log(0.5) doesn't get rounded or clamped in the nHashFuncs calculation
|
|
|
|
* - nElements is even, so that nEntriesPerGeneration == nElements / 2
|
|
|
|
*
|
|
|
|
* Then we get a more accurate estimate for filter bytes:
|
|
|
|
*
|
|
|
|
* 3/(log(256)*log(2)) * log(1/fpRate) * nElements
|
2015-04-24 19:14:45 +02:00
|
|
|
*/
|
|
|
|
class CRollingBloomFilter
|
|
|
|
{
|
|
|
|
public:
|
2015-07-27 18:58:00 +02:00
|
|
|
// A random bloom filter calls GetRand() at creation time.
|
|
|
|
// Don't create global CRollingBloomFilter objects, as they may be
|
|
|
|
// constructed before the randomizer is properly initialized.
|
2017-05-18 10:08:56 +02:00
|
|
|
CRollingBloomFilter(const unsigned int nElements, const double nFPRate);
|
2015-04-24 19:14:45 +02:00
|
|
|
|
|
|
|
void insert(const std::vector<unsigned char>& vKey);
|
2015-07-17 12:42:43 +02:00
|
|
|
void insert(const uint256& hash);
|
2015-04-24 19:14:45 +02:00
|
|
|
bool contains(const std::vector<unsigned char>& vKey) const;
|
2015-07-17 12:42:43 +02:00
|
|
|
bool contains(const uint256& hash) const;
|
2015-04-24 19:14:45 +02:00
|
|
|
|
2015-07-27 18:58:00 +02:00
|
|
|
void reset();
|
2015-04-24 19:14:45 +02:00
|
|
|
|
|
|
|
private:
|
2015-12-03 13:35:55 +01:00
|
|
|
int nEntriesPerGeneration;
|
|
|
|
int nEntriesThisGeneration;
|
|
|
|
int nGeneration;
|
2016-05-09 08:31:14 +02:00
|
|
|
std::vector<uint64_t> data;
|
2015-12-03 13:35:55 +01:00
|
|
|
unsigned int nTweak;
|
|
|
|
int nHashFuncs;
|
|
|
|
};
|
2015-04-24 19:14:45 +02:00
|
|
|
|
2014-08-28 22:21:03 +02:00
|
|
|
#endif // BITCOIN_BLOOM_H
|