const SECRET = process.env.FEISTEL_SECRET || "change-me"; const ROUNDS = 8; const HALF = 20; const MASK = (1 << HALF) - 1; const CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; function roundFn(right: number, round: number): number { const h = new Bun.CryptoHasher("sha256").update(SECRET + ":" + round + ":" + right).digest(); return (h[0] << 12 | h[1] << 4 | h[2] >> 4) & MASK; } function toBase62(n: number): string { let s = ""; for (let i = 0; i < 7; i++) { s = CHARS[n % 62] + s; n = Math.floor(n / 62); } return s; } function fromBase62(s: string): number { let n = 0; for (const c of s) n = n * 62 + CHARS.indexOf(c); return n; } export function encodeId(val: number): string { let left = Math.floor(val / (MASK + 1)) & MASK; let right = val & MASK; for (let i = 0; i < ROUNDS; i++) { const tmp = (left ^ roundFn(right, i)) & MASK; left = right; right = tmp; } return toBase62(left * (MASK + 1) + right); } export function decodeId(s: string): number { const val = fromBase62(s); let left = Math.floor(val / (MASK + 1)) & MASK; let right = val & MASK; for (let i = ROUNDS - 1; i >= 0; i--) { const tmp = (right ^ roundFn(left, i)) & MASK; right = left; left = tmp; } return left * (MASK + 1) + right; }