bitcoin Bloom过滤器

 

 

3.2 Bloom过滤器

    bloom过滤器是一种基于概率的过滤方法。其原理概括起来就是将输入数据用若干个Hash函数映射到二进制串中的若干个bit上。

    下图是一个用3个hash函数将输入映射到长度为16的二进制串中的例子:

    

    3个hash函数K1,K2,K3将输入映射后的结果分别为3,1,14,于是将二级制串中的第3,1和14位置1。

    bloom过滤器的最常用的情景就是在海量的数据集中查找某个元素是否存在,这也是BAT面试题中经常会出现的问题。由于数据量巨大,需要的存储空间也会非常大,为了节省空间,可以使用bloom过滤器。

    当查找的时候,只需要将输入代入到哈希函数,然后检查二进制串中对应的位是否被置1。例如对于上图中的例子,为了检查输入A是否存在,只需要用将A代入K1,K2,K3,然后分别检查第3,1,14位是否为1,如果都为1,则A很有可能(注意是可能)存在。

    在比特币中,Bloom过滤器主要也是用在SPV节点的实现上,在查询交易的同时又不暴露用户的钱包地址隐私。

    比特币的bloom过滤器的实现位于bloom.cpp文件中,简单过一下源码:

    (1) 构造

    bloom过滤器的构造函数如下:    

CBloomFilter::CBloomFilter(const unsigned int nElements, const double nFPRate, const unsigned int nTweakIn, unsigned char nFlagsIn) :
/*** The ideal size for a bloom filter with a given number of elements and false positive rate is:
* - nElements * log(fp rate) / ln(2)^2
* We ignore filter parameters which will create a bloom filter larger than the protocol limits
*/
vData(std::min((unsigned int)(-1 / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8),
/*** The ideal number of hash functions is filter size 
* ln(2) / number of elements
* Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits
* See https://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas
*/
isFull(false),
isEmpty(true),
nHashFuncs(std::min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
nTweak(nTweakIn),
nFlags(nFlagsIn){}
  1.  

    vData是存放二进制串的向量,根据代码注释,理想的向量的长度未-nElements * log(fp rate) / ln2^2,至于为什么这么算就不是很清楚了,数学学的好的同学可以在评论区里指导一下。

    nHashFuncs是对每个输入进行多少次hash。

    (2) 插入元素到bloom过滤器中

void CBloomFilter::insert(const std::vector<unsigned char>& vKey){
if (isFull)
return;
for (unsigned int i = 0; i < nHashFuncs; i++){
unsigned int nIndex = Hash(i, vKey);
// Sets bit nIndex of vData
vData[nIndex >> 3] |= (1 << (7 & nIndex));}isEmpty = false;
}
  1.  

    代码很简单,对每个输入,进行nHashFuncs次Hash运算,将映射到的值写入向量vData对应的bit。

    这里Hash的计算方法关注一下:

inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const{
// 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values.
return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8);
}
  1.  

  2.  

    注意一下这里的MurmurHash3,这是一个非加密型的hash算法,由Austin Appleby于2008年发明,具有抗碰撞性强、速度快的特点,目前已经被很多知名的开源项目所使用,而发明此算法的Austin Appleby本人也被google聘用(论数学的重要性),现在MurmurHash已经到了第3个版本,下面的链接详细的对此算法进行了介绍,并包含伪码:

    murmurHash介绍

    比特币murmurhash3的实现如下,可以结合上面链接中的伪码看:

unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash){
// The following is MurmurHash3 (x86_32), see http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
uint32_t h1 = nHashSeed;
const uint32_t c1 = 0xcc9e2d51;
const uint32_t c2 = 0x1b873593;
const int nblocks = vDataToHash.size() / 4;
//----------
// body
const uint8_t* blocks = vDataToHash.data();
for (int i = 0; i < nblocks; ++i) {
uint32_t k1 = ReadLE32(blocks + i*4);
k1 *= c1;
k1 = ROTL32(k1, 15);
k1 *= c2;
h1 ^= k1;
h1 = ROTL32(h1, 13);
h1 = h1 * 5 + 0xe6546b64;}
//----------
// tail
const uint8_t* tail = vDataToHash.data() + nblocks * 4;
uint32_t k1 = 0;
switch (vDataToHash.size() & 3) {
case 3:k1 ^= tail[2] << 16;
case 2:k1 ^= tail[1] << 8;
case 1:k1 ^= tail[0];
k1 *= c1;
k1 = ROTL32(k1, 15);
k1 *= c2;
h1 ^= k1;
}
//----------
// finalization
h1 ^= vDataToHash.size();
h1 ^= h1 >> 16;
h1 *= 0x85ebca6b;
h1 ^= h1 >> 13;
h1 *= 0xc2b2ae35;
h1 ^= h1 >> 16;
return h1;
}
  1.  

    关于merkle树和bloom过滤器的使用,可以参考比特币改进协议BIP37 :

    BIP37改进协议

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值