diff --git a/lib/utils/gcs.js b/lib/utils/gcs.js index 9dc0e873..69faf19d 100644 --- a/lib/utils/gcs.js +++ b/lib/utils/gcs.js @@ -12,6 +12,7 @@ var crypto = require('../crypto/crypto'); var siphash24 = require('../crypto/siphash'); var SCRATCH = Buffer.allocUnsafe(64); var DUMMY = Buffer.allocUnsafe(0); +var EOF = new Int64(-1); /** * GCSFilter @@ -21,7 +22,7 @@ var DUMMY = Buffer.allocUnsafe(0); function GCSFilter() { this.n = 0; this.p = 0; - this.m = Int64(0); + this.m = new Int64(0); this.data = DUMMY; } @@ -41,17 +42,14 @@ GCSFilter.prototype.header = function header(prev) { GCSFilter.prototype.match = function match(key, data) { var br = new BitReader(this.data); var term = siphash(data, key).imod(this.m); - var last = Int64(0); + var last = new Int64(0); var value; while (last.lt(term)) { - try { - value = this.readU64(br); - } catch (e) { - if (e.message === 'EOF') - return false; - throw e; - } + value = this.readU64(br); + + if (value === EOF) + return false; value.iadd(last); @@ -66,7 +64,7 @@ GCSFilter.prototype.match = function match(key, data) { GCSFilter.prototype.matchAny = function matchAny(key, items) { var br = new BitReader(this.data); - var last1 = Int64(0); + var last1 = new Int64(0); var values = []; var i, item, hash, last2, cmp, value; @@ -98,13 +96,10 @@ GCSFilter.prototype.matchAny = function matchAny(key, items) { return false; } - try { - value = this.readU64(br); - } catch (e) { - if (e.message === 'EOF') - return false; - throw e; - } + value = this.readU64(br); + + if (value === EOF) + return false; last1.iadd(value); } @@ -113,18 +108,26 @@ GCSFilter.prototype.matchAny = function matchAny(key, items) { }; GCSFilter.prototype.readU64 = function readU64(br) { - var num = Int64(0); - var bit = br.readBit(); + try { + return this._readU64(br); + } catch (e) { + if (e.message === 'EOF') + return EOF; + throw e; + } +}; + +GCSFilter.prototype._readU64 = function _readU64(br) { + var num = new Int64(0); var rem; - while (bit) { + // Unary + while (br.readBit()) num.iaddn(1); - bit = br.readBit(); - } rem = br.readBits64(this.p); - return num.ishln(this.p).iadd(rem); + return num.ishln(this.p).ior(rem); }; GCSFilter.prototype.toBytes = function toBytes() { @@ -153,10 +156,16 @@ GCSFilter.prototype.toNPBytes = function toNPBytes() { return data; }; +GCSFilter.prototype.toRaw = function toRaw() { + assert(this.p === 20); + return this.toNBytes(); +}; + GCSFilter.prototype.fromItems = function fromItems(P, key, items) { + var bw = new BitWriter(); + var last = new Int64(0); var values = []; - var last = Int64(0); - var i, bw, item, hash, value, rem; + var i, item, hash, value, rem; assert(typeof P === 'number' && isFinite(P)); assert(P >= 0 && P <= 32); @@ -172,8 +181,6 @@ GCSFilter.prototype.fromItems = function fromItems(P, key, items) { this.p = P; this.m = Int64(this.n).ishln(this.p); - bw = new BitWriter(); - for (i = 0; i < items.length; i++) { item = items[i]; assert(Buffer.isBuffer(item)); @@ -254,6 +261,10 @@ GCSFilter.prototype.fromNPBytes = function fromNPBytes(data) { return this.fromBytes(N, P, data.slice(5)); }; +GCSFilter.prototype.fromRaw = function fromRaw(data) { + return this.fromNBytes(20, data); +}; + GCSFilter.prototype.fromBlock = function fromBlock(block) { var hash = block.hash(); var key = hash.slice(0, 16); @@ -322,6 +333,10 @@ GCSFilter.fromNPBytes = function fromNPBytes(data) { return new GCSFilter().fromNPBytes(data); }; +GCSFilter.fromRaw = function fromRaw(data) { + return new GCSFilter().fromRaw(data); +}; + GCSFilter.fromBlock = function fromBlock(block) { return new GCSFilter().fromBlock(block); }; @@ -356,7 +371,7 @@ BitWriter.prototype.writeBit = function writeBit(bit) { this.remain--; }; -BitWriter.prototype.writeOneByte = function writeOneByte(ch) { +BitWriter.prototype.writeByte = function writeByte(ch) { var index; if (this.remain === 0) { @@ -366,9 +381,9 @@ BitWriter.prototype.writeOneByte = function writeOneByte(ch) { index = this.stream.length - 1; - this.stream[index] |= ch >> (8 - this.remain); + this.stream[index] |= (ch >> (8 - this.remain)) & 0xff; this.stream.push(0); - this.stream[index + 1] = ch << this.remain; + this.stream[index + 1] = (ch << this.remain) & 0xff; }; BitWriter.prototype.writeBits = function writeBits(num, count) { @@ -381,8 +396,7 @@ BitWriter.prototype.writeBits = function writeBits(num, count) { while (count >= 8) { ch = num >>> 24; - this.writeOneByte(ch); - + this.writeByte(ch); num <<= 8; count -= 8; } @@ -391,11 +405,14 @@ BitWriter.prototype.writeBits = function writeBits(num, count) { bit = num >>> 31; this.writeBit(bit); num <<= 1; - count--; + count -= 1; } }; BitWriter.prototype.writeBits64 = function writeBits64(num, count) { + assert(count >= 0); + assert(count <= 64); + if (count > 32) { this.writeBits(num.hi, count - 32); this.writeBits(num.lo, 32); @@ -405,12 +422,11 @@ BitWriter.prototype.writeBits64 = function writeBits64(num, count) { }; BitWriter.prototype.render = function render() { - var stream = this.stream; - var data = Buffer.allocUnsafe(stream.length); + var data = Buffer.allocUnsafe(this.stream.length); var i; - for (i = 0; i < stream.length; i++) - data[i] = stream[i]; + for (i = 0; i < this.stream.length; i++) + data[i] = this.stream[i]; return data; }; @@ -421,7 +437,7 @@ BitWriter.prototype.render = function render() { */ function BitReader(data) { - this.stream = copy(data); + this.stream = data; this.pos = 0; this.remain = 8; } @@ -441,13 +457,9 @@ BitReader.prototype.readBit = function readBit() { this.remain = 8; } - bit = this.stream[this.pos] & 0x80; + this.remain -= 1; - this.stream[this.pos] <<= 1; - this.stream[this.pos] &= 0xff; - this.remain--; - - return bit !== 0 ? 1 : 0; + return (this.stream[this.pos] >> this.remain) & 1; }; BitReader.prototype.readByte = function readByte() { @@ -471,7 +483,9 @@ BitReader.prototype.readByte = function readByte() { return ch; } - ch = this.stream[this.pos]; + ch = this.stream[this.pos] & ((1 << this.remain) - 1); + ch <<= 8 - this.remain; + this.pos += 1; if (this.pos >= this.stream.length) @@ -479,31 +493,24 @@ BitReader.prototype.readByte = function readByte() { ch |= this.stream[this.pos] >> this.remain; - this.stream[this.pos] <<= (8 - this.remain); - this.stream[this.pos] &= 0xff; - return ch; }; BitReader.prototype.readBits = function readBits(count) { var num = 0; - var ch, bit; assert(count >= 0); assert(count <= 32); while (count >= 8) { num <<= 8; - ch = this.readByte(); - num |= ch; + num |= this.readByte(); count -= 8; } while (count > 0) { num <<= 1; - bit = this.readBit(); - if (bit) - num |= 1; + num |= this.readBit(); count -= 1; } @@ -511,16 +518,19 @@ BitReader.prototype.readBits = function readBits(count) { }; BitReader.prototype.readBits64 = function readBits(count) { - var n = new Int64(); + var num = new Int64(); + + assert(count >= 0); + assert(count <= 64); if (count > 32) { - n.hi = this.readBits(count - 32); - n.lo = this.readBits(32); + num.hi = this.readBits(count - 32); + num.lo = this.readBits(32); } else { - n.lo = this.readBits(count); + num.lo = this.readBits(count); } - return n; + return num; }; /* @@ -532,14 +542,11 @@ function compare(a, b) { } function siphash(data, key) { + var num = new Int64(); var hash = siphash24(data, key); - return Int64().join(hash.hi, hash.lo); -} - -function copy(data) { - var clone = Buffer.allocUnsafe(data.length); - data.copy(clone, 0, 0, data.length); - return clone; + num.hi = hash.hi | 0; + num.lo = hash.lo | 0; + return num; } function getPushes(items, script) {