fcoin/lib/bcoin/bloom.js
Christopher Jeffrey 73832de55f bloom refactor.
2016-04-01 21:25:48 -07:00

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;