inthash
Version:
Efficient integer hashing library using Knuth's multiplicative method for Javascript and Typescript, perfect for obfuscating sequential numbers.
96 lines (95 loc) • 2.88 kB
JavaScript
import { randomPrime } from "./prime.js";
function modInv(a, b) {
let t = 0n;
let r = b;
let nextT = 1n;
let nextR = a;
while (nextR > 0) {
const q = ~~(r / nextR);
const [lastT, lastR] = [t, r];
[t, r] = [nextT, nextR];
[nextT, nextR] = [lastT - q * nextT, lastR - q * nextR];
}
return t < 0 ? t + b : t;
}
function generateXor(bits) {
let result = 0n;
for (let i = 0; i < bits; i++) {
result = (result << 1n) | (Math.random() < 0.5 ? 1n : 0n);
}
return result;
}
export class Hasher {
static generate(bits) {
bits = bits ?? Number.MAX_SAFE_INTEGER.toString(2).length; // default to Number.MAX_SAFE_INTEGER
if (bits < 2) {
throw new Error("bits must be greater than 2");
}
const modBase = 2n ** BigInt(bits);
const prime = randomPrime(bits);
return {
bits,
prime: prime.toString(),
inverse: modInv(prime, modBase).toString(),
xor: generateXor(bits).toString(),
};
}
constructor({ bits, prime, inverse, xor }) {
Object.defineProperty(this, "_prime", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_inverse", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_xor", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_mask", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_max", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this._prime = BigInt(prime);
this._inverse = BigInt(inverse);
this._xor = BigInt(xor);
this._mask = 2n ** BigInt(bits) - 1n;
this._max = (1n << BigInt(bits)) - 1n;
}
encode(n) {
if (typeof n === "string") {
return this.encode(BigInt(n)).toString();
}
if (typeof n === "number") {
return Number(this.encode(BigInt(n)));
}
if (n > this._max) {
console.warn(`input ${n} is greater than max ${this._max}`);
}
return n * this._prime & this._mask ^ this._xor;
}
decode(n) {
if (typeof n === "string") {
return this.decode(BigInt(n)).toString();
}
if (typeof n === "number") {
return Number(this.decode(BigInt(n)));
}
return (n ^ this._xor) * this._inverse & this._mask;
}
}