UNPKG

@waku/rln

Version:

RLN (Rate Limiting Nullifier) implementation for Waku

368 lines (365 loc) 10.6 kB
import { decodeUint8Array, encodingLength } from '../../../../uint8-varint/dist/src/index.js'; import { readFloatLE, readDoubleLE } from './float.js'; import { LongBits } from './longbits.js'; import { read } from './utf8.js'; /* istanbul ignore next */ function indexOutOfRange(reader, writeLength) { return RangeError(`index out of range: ${reader.pos} + ${writeLength ?? 1} > ${reader.len}`); } function readFixed32End(buf, end) { return (buf[end - 4] | buf[end - 3] << 8 | buf[end - 2] << 16 | buf[end - 1] << 24) >>> 0; } /** * Constructs a new reader instance using the specified buffer. */ class Uint8ArrayReader { buf; pos; len; _slice = Uint8Array.prototype.subarray; constructor(buffer) { /** * Read buffer */ this.buf = buffer; /** * Read buffer position */ this.pos = 0; /** * Read buffer length */ this.len = buffer.length; } /** * Reads a varint as an unsigned 32 bit value */ uint32() { let value = 4294967295; value = (this.buf[this.pos] & 127) >>> 0; if (this.buf[this.pos++] < 128) return value; value = (value | (this.buf[this.pos] & 127) << 7) >>> 0; if (this.buf[this.pos++] < 128) return value; value = (value | (this.buf[this.pos] & 127) << 14) >>> 0; if (this.buf[this.pos++] < 128) return value; value = (value | (this.buf[this.pos] & 127) << 21) >>> 0; if (this.buf[this.pos++] < 128) return value; value = (value | (this.buf[this.pos] & 15) << 28) >>> 0; if (this.buf[this.pos++] < 128) return value; if ((this.pos += 5) > this.len) { this.pos = this.len; throw indexOutOfRange(this, 10); } return value; } /** * Reads a varint as a signed 32 bit value */ int32() { return this.uint32() | 0; } /** * Reads a zig-zag encoded varint as a signed 32 bit value */ sint32() { const value = this.uint32(); return value >>> 1 ^ -(value & 1) | 0; } /** * Reads a varint as a boolean */ bool() { return this.uint32() !== 0; } /** * Reads fixed 32 bits as an unsigned 32 bit integer */ fixed32() { if (this.pos + 4 > this.len) { throw indexOutOfRange(this, 4); } const res = readFixed32End(this.buf, this.pos += 4); return res; } /** * Reads fixed 32 bits as a signed 32 bit integer */ sfixed32() { if (this.pos + 4 > this.len) { throw indexOutOfRange(this, 4); } const res = readFixed32End(this.buf, this.pos += 4) | 0; return res; } /** * Reads a float (32 bit) as a number */ float() { if (this.pos + 4 > this.len) { throw indexOutOfRange(this, 4); } const value = readFloatLE(this.buf, this.pos); this.pos += 4; return value; } /** * Reads a double (64 bit float) as a number */ double() { /* istanbul ignore if */ if (this.pos + 8 > this.len) { throw indexOutOfRange(this, 4); } const value = readDoubleLE(this.buf, this.pos); this.pos += 8; return value; } /** * Reads a sequence of bytes preceded by its length as a varint */ bytes() { const length = this.uint32(); const start = this.pos; const end = this.pos + length; /* istanbul ignore if */ if (end > this.len) { throw indexOutOfRange(this, length); } this.pos += length; return start === end // fix for IE 10/Win8 and others' subarray returning array of size 1 ? new Uint8Array(0) : this.buf.subarray(start, end); } /** * Reads a string preceded by its byte length as a varint */ string() { const bytes = this.bytes(); return read(bytes, 0, bytes.length); } /** * Skips the specified number of bytes if specified, otherwise skips a varint */ skip(length) { if (typeof length === 'number') { /* istanbul ignore if */ if (this.pos + length > this.len) { throw indexOutOfRange(this, length); } this.pos += length; } else { do { /* istanbul ignore if */ if (this.pos >= this.len) { throw indexOutOfRange(this); } } while ((this.buf[this.pos++] & 128) !== 0); } return this; } /** * Skips the next element of the specified wire type */ skipType(wireType) { switch (wireType) { case 0: this.skip(); break; case 1: this.skip(8); break; case 2: this.skip(this.uint32()); break; case 3: while ((wireType = this.uint32() & 7) !== 4) { this.skipType(wireType); } break; case 5: this.skip(4); break; /* istanbul ignore next */ default: throw Error(`invalid wire type ${wireType} at offset ${this.pos}`); } return this; } readLongVarint() { // tends to deopt with local vars for octet etc. const bits = new LongBits(0, 0); let i = 0; if (this.len - this.pos > 4) { // fast route (lo) for (; i < 4; ++i) { // 1st..4th bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0; if (this.buf[this.pos++] < 128) { return bits; } } // 5th bits.lo = (bits.lo | (this.buf[this.pos] & 127) << 28) >>> 0; bits.hi = (bits.hi | (this.buf[this.pos] & 127) >> 4) >>> 0; if (this.buf[this.pos++] < 128) { return bits; } i = 0; } else { for (; i < 3; ++i) { /* istanbul ignore if */ if (this.pos >= this.len) { throw indexOutOfRange(this); } // 1st..3th bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0; if (this.buf[this.pos++] < 128) { return bits; } } // 4th bits.lo = (bits.lo | (this.buf[this.pos++] & 127) << i * 7) >>> 0; return bits; } if (this.len - this.pos > 4) { // fast route (hi) for (; i < 5; ++i) { // 6th..10th bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0; if (this.buf[this.pos++] < 128) { return bits; } } } else { for (; i < 5; ++i) { if (this.pos >= this.len) { throw indexOutOfRange(this); } // 6th..10th bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0; if (this.buf[this.pos++] < 128) { return bits; } } } throw Error('invalid varint encoding'); } readFixed64() { if (this.pos + 8 > this.len) { throw indexOutOfRange(this, 8); } const lo = readFixed32End(this.buf, this.pos += 4); const hi = readFixed32End(this.buf, this.pos += 4); return new LongBits(lo, hi); } /** * Reads a varint as a signed 64 bit value */ int64() { return this.readLongVarint().toBigInt(); } /** * Reads a varint as a signed 64 bit value returned as a possibly unsafe * JavaScript number */ int64Number() { return this.readLongVarint().toNumber(); } /** * Reads a varint as a signed 64 bit value returned as a string */ int64String() { return this.readLongVarint().toString(); } /** * Reads a varint as an unsigned 64 bit value */ uint64() { return this.readLongVarint().toBigInt(true); } /** * Reads a varint as an unsigned 64 bit value returned as a possibly unsafe * JavaScript number */ uint64Number() { const value = decodeUint8Array(this.buf, this.pos); this.pos += encodingLength(value); return value; } /** * Reads a varint as an unsigned 64 bit value returned as a string */ uint64String() { return this.readLongVarint().toString(true); } /** * Reads a zig-zag encoded varint as a signed 64 bit value */ sint64() { return this.readLongVarint().zzDecode().toBigInt(); } /** * Reads a zig-zag encoded varint as a signed 64 bit value returned as a * possibly unsafe JavaScript number */ sint64Number() { return this.readLongVarint().zzDecode().toNumber(); } /** * Reads a zig-zag encoded varint as a signed 64 bit value returned as a * string */ sint64String() { return this.readLongVarint().zzDecode().toString(); } /** * Reads fixed 64 bits */ fixed64() { return this.readFixed64().toBigInt(); } /** * Reads fixed 64 bits returned as a possibly unsafe JavaScript number */ fixed64Number() { return this.readFixed64().toNumber(); } /** * Reads fixed 64 bits returned as a string */ fixed64String() { return this.readFixed64().toString(); } /** * Reads zig-zag encoded fixed 64 bits */ sfixed64() { return this.readFixed64().toBigInt(); } /** * Reads zig-zag encoded fixed 64 bits returned as a possibly unsafe * JavaScript number */ sfixed64Number() { return this.readFixed64().toNumber(); } /** * Reads zig-zag encoded fixed 64 bits returned as a string */ sfixed64String() { return this.readFixed64().toString(); } } function createReader(buf) { return new Uint8ArrayReader(buf instanceof Uint8Array ? buf : buf.subarray()); } export { Uint8ArrayReader, createReader };