UNPKG

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.71 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.randomPrime = exports.isPrimeMillerRabin = void 0; function modPow(x, y, p) { x = x % p; let result = 1n; while (y > 0n) { if (y & 1n) { result = (result * x) % p; } y = y / 2n; x = (x * x) % p; } return result; } function randomBigInt(range) { const n = range.toString(2).length; if (n === 1) { return 0n; } if (n < 52) { return BigInt(Math.floor(Math.random() * Number(range))); } return BigInt(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)); // TODO } // https://github.com/openssl/openssl/blob/4cedf30e995f9789cf6bb103e248d33285a84067/crypto/bn/bn_prime.c#L337 function isPrimeMillerRabin(w, iterations) { if (w === 2n) { return true; } if (w < 2n || w % 2n === 0n) { return false; } const w1 = w - 1n; const w3 = w - 3n; let a = 1; let m = w1; // (Step 1) Calculate largest integer 'a' such that 2^a divides w-1 // (Step 2) m = (w-1) / 2^a while (m % 2n === 0n) { a++; m /= 2n; } // TODO montgomery iterations = iterations ?? w.toString(2).length > 2048 ? 128 : 64; // (Step 4) outer_loop: for (let i = 0; i < iterations; i++) { // (Step 4.1) obtain a Random string of bits b where 1 < b < w-1 */ const b = randomBigInt(w3) + 2n; // (Step 4.5) z = b^m mod w // in openssl, Montgomery modular multiplication (TODO) let z = modPow(b, m, w); /* (Step 4.6) if (z = 1 or z = w-1) */ if (z === 1n || z === w1) { continue outer_loop; } /* (Step 4.7) for j = 1 to a-1 */ for (let j = 1; j < a; j++) { // (Step 4.7.1 - 4.7.2) x = z, z = x^2 mod w z = modPow(z, 2n, w); // (Step 4.7.3) if (z === w1) { continue outer_loop; } // (Step 4.7.4) if (z === 1n) { return false; } } return false; } return true; } exports.isPrimeMillerRabin = isPrimeMillerRabin; function randomOdd(bits) { let result = 1n; for (let i = 2; i < bits; i++) { result = (result << 1n) | (Math.random() < 0.5 ? 1n : 0n); } return (result << 1n) | 1n; } function randomPrime(bits) { if (bits < 2) { return 1n; } let result = randomOdd(bits); while (!isPrimeMillerRabin(result)) { result += 2n; if (result.toString(2).length > bits) { result = randomOdd(bits); } } return result; } exports.randomPrime = randomPrime;