{"version":3,"file":"murmur.cjs","sources":["../../../src/hashing/murmur.ts"],"sourcesContent":["/*\n * Implementation of murmur hash based on the Composites polyfill implementation:\n * https://github.com/tc39/proposal-composites\n */\n\nconst RANDOM_SEED = randomHash()\nconst STRING_MARKER = randomHash()\nconst BIG_INT_MARKER = randomHash()\nconst NEG_BIG_INT_MARKER = randomHash()\nconst SYMBOL_MARKER = randomHash()\n\nexport type Hash = number\n\nexport function randomHash() {\n  return (Math.random() * (2 ** 31 - 1)) >>> 0\n}\n\nexport interface Hasher {\n  update: (val: symbol | string | number | bigint) => void\n  digest: () => number\n}\n\n// Allocate these once, outside the hot path\nconst buf = new ArrayBuffer(8)\n// dv and u8 are 2 different views on the same buffer `buf`\nconst dv = new DataView(buf)\nconst u8 = new Uint8Array(buf)\n\n/**\n * This implementation of Murmur hash uses a random initial seed and random markers.\n * This means that hashes aren't deterministic across app restarts.\n * This is intentional in the composites polyfill to be resistent to hash-flooding attacks\n * where malicious users would precompute lots of different objects whose hashes collide with each other.\n *\n * Currently, for ts/db-ivm this is fine because we don't persist client state.\n * However, when we will introduce persistence we will either need to store the seeds or remove the randomness\n * to ensure deterministic hashes across app restarts.\n */\nexport class MurmurHashStream implements Hasher {\n  private hash: number = RANDOM_SEED\n  private length = 0\n  private carry = 0\n  private carryBytes = 0\n\n  private _mix(k1: number): void {\n    k1 = Math.imul(k1, 0xcc9e2d51)\n    k1 = (k1 << 15) | (k1 >>> 17)\n    k1 = Math.imul(k1, 0x1b873593)\n    this.hash ^= k1\n    this.hash = (this.hash << 13) | (this.hash >>> 19)\n    this.hash = Math.imul(this.hash, 5) + 0xe6546b64\n  }\n\n  writeByte(byte: number): void {\n    this.carry |= (byte & 0xff) << (8 * this.carryBytes)\n    this.carryBytes++\n    this.length++\n\n    if (this.carryBytes === 4) {\n      this._mix(this.carry >>> 0)\n      this.carry = 0\n      this.carryBytes = 0\n    }\n  }\n\n  update(chunk: symbol | string | number | bigint): void {\n    switch (typeof chunk) {\n      case `symbol`: {\n        this.update(SYMBOL_MARKER)\n        const description = chunk.description\n        if (!description) {\n          return\n        }\n\n        for (let i = 0; i < description.length; i++) {\n          const code = description.charCodeAt(i)\n          this.writeByte(code & 0xff)\n          this.writeByte((code >>> 8) & 0xff)\n        }\n        return\n      }\n      case `string`:\n        this.update(STRING_MARKER)\n        for (let i = 0; i < chunk.length; i++) {\n          const code = chunk.charCodeAt(i)\n          this.writeByte(code & 0xff)\n          this.writeByte((code >>> 8) & 0xff)\n        }\n        return\n      case `number`:\n        dv.setFloat64(0, chunk, true) // fixed little-endian\n        this.writeByte(u8[0]!)\n        this.writeByte(u8[1]!)\n        this.writeByte(u8[2]!)\n        this.writeByte(u8[3]!)\n        this.writeByte(u8[4]!)\n        this.writeByte(u8[5]!)\n        this.writeByte(u8[6]!)\n        this.writeByte(u8[7]!)\n        return\n      case `bigint`: {\n        let value = chunk\n        if (value < 0n) {\n          value = -value\n          this.update(NEG_BIG_INT_MARKER)\n        } else {\n          this.update(BIG_INT_MARKER)\n        }\n        while (value > 0n) {\n          this.writeByte(Number(value & 0xffn))\n          value >>= 8n\n        }\n        if (chunk === 0n) this.writeByte(0)\n        return\n      }\n      default:\n        throw new TypeError(`Unsupported input type: ${typeof chunk}`)\n    }\n  }\n\n  digest(): number {\n    if (this.carryBytes > 0) {\n      let k1 = this.carry >>> 0\n      k1 = Math.imul(k1, 0xcc9e2d51)\n      k1 = (k1 << 15) | (k1 >>> 17)\n      k1 = Math.imul(k1, 0x1b873593)\n      this.hash ^= k1\n    }\n\n    this.hash ^= this.length\n    this.hash ^= this.hash >>> 16\n    this.hash = Math.imul(this.hash, 0x85ebca6b)\n    this.hash ^= this.hash >>> 13\n    this.hash = Math.imul(this.hash, 0xc2b2ae35)\n    this.hash ^= this.hash >>> 16\n\n    return this.hash >>> 0\n  }\n}\n"],"names":[],"mappings":"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"}