165 lines
2.8 KiB
JavaScript
165 lines
2.8 KiB
JavaScript
/**
|
|
* bloom.js - bloom filter for bcoin
|
|
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
|
|
* https://github.com/indutny/bcoin
|
|
*/
|
|
|
|
var utils = require('./utils');
|
|
|
|
/**
|
|
* Bloom
|
|
*/
|
|
|
|
function Bloom(size, n, tweak) {
|
|
if (!(this instanceof Bloom))
|
|
return new Bloom(size, n, tweak);
|
|
|
|
this.filter = new Buffer(Math.ceil(size / 8));
|
|
this.size = size;
|
|
this.n = n;
|
|
this.tweak = tweak;
|
|
|
|
this.reset();
|
|
}
|
|
|
|
Bloom.prototype.hash = function hash(val, n) {
|
|
return murmur(val, sum32(mul32(n, 0xfba4c795), this.tweak)) % this.size;
|
|
};
|
|
|
|
Bloom.prototype.reset = function reset() {
|
|
this.filter.fill(0);
|
|
};
|
|
|
|
Bloom.prototype.add = function add(val, enc) {
|
|
var i, bit, pos, shift;
|
|
|
|
val = utils.toBuffer(val, enc);
|
|
|
|
for (i = 0; i < this.n; i++) {
|
|
bit = this.hash(val, i);
|
|
pos = 1 << (bit & 0x1f);
|
|
shift = bit >> 5;
|
|
shift *= 4;
|
|
|
|
utils.writeU32(this.filter, utils.readU32(this.filter, shift) | pos, shift);
|
|
}
|
|
};
|
|
|
|
Bloom.prototype.test = function test(val, enc) {
|
|
var i, bit, pos, shift;
|
|
|
|
val = utils.toBuffer(val, enc);
|
|
|
|
for (i = 0; i < this.n; i++) {
|
|
bit = this.hash(val, i);
|
|
pos = 1 << (bit & 0x1f);
|
|
shift = bit >> 5;
|
|
shift *= 4;
|
|
|
|
if ((utils.readU32(this.filter, shift) & pos) === 0)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
Bloom.prototype.toBuffer = function toBuffer() {
|
|
return this.filter;
|
|
};
|
|
|
|
function mul32(a, b) {
|
|
var alo = a & 0xffff;
|
|
var blo = b & 0xffff;
|
|
var ahi = a >>> 16;
|
|
var bhi = b >>> 16;
|
|
var r, lo, hi;
|
|
|
|
lo = alo * blo;
|
|
hi = (ahi * blo + bhi * alo) & 0xffff;
|
|
|
|
hi += lo >>> 16;
|
|
lo &= 0xffff;
|
|
r = (hi << 16) | lo;
|
|
|
|
if (r < 0)
|
|
r += 0x100000000;
|
|
|
|
return r;
|
|
}
|
|
|
|
function sum32(a, b) {
|
|
var r = (a + b) & 0xffffffff;
|
|
|
|
if (r < 0)
|
|
r += 0x100000000;
|
|
|
|
return r;
|
|
}
|
|
|
|
function rotl32(w, b) {
|
|
return (w << b) | (w >>> (32 - b));
|
|
}
|
|
|
|
function murmur(data, seed) {
|
|
var c1 = 0xcc9e2d51;
|
|
var c2 = 0x1b873593;
|
|
var r1 = 15;
|
|
var r2 = 13;
|
|
var m = 5;
|
|
var n = 0xe6546b64;
|
|
var hash = seed;
|
|
var i, w, r, j;
|
|
|
|
data = utils.toBuffer(data);
|
|
|
|
for (i = 0; i + 4 <= data.length; i += 4) {
|
|
w = data[i]
|
|
| (data[i + 1] << 8)
|
|
| (data[i + 2] << 16)
|
|
| (data[i + 3] << 24);
|
|
|
|
w = mul32(w, c1);
|
|
w = rotl32(w, r1);
|
|
w = mul32(w, c2);
|
|
|
|
hash ^= w;
|
|
hash = rotl32(hash, r2);
|
|
hash = mul32(hash, m);
|
|
hash = sum32(hash, n);
|
|
}
|
|
|
|
if (i !== data.length) {
|
|
r = 0;
|
|
for (j = data.length - 1; j >= i; j--)
|
|
r = (r << 8) | data[j];
|
|
|
|
r = mul32(r, c1);
|
|
r = rotl32(r, r1);
|
|
if (r < 0)
|
|
r += 0x100000000;
|
|
r = mul32(r, c2);
|
|
|
|
hash ^= r;
|
|
}
|
|
|
|
hash ^= data.length;
|
|
hash ^= hash >>> 16;
|
|
hash = mul32(hash, 0x85ebca6b);
|
|
hash ^= hash >>> 13;
|
|
hash = mul32(hash, 0xc2b2ae35);
|
|
hash ^= hash >>> 16;
|
|
|
|
if (hash < 0)
|
|
hash += 0x100000000;
|
|
|
|
return hash;
|
|
}
|
|
|
|
Bloom.hash = murmur;
|
|
|
|
/**
|
|
* Expose
|
|
*/
|
|
|
|
module.exports = Bloom;
|