bigint-mod-arith/dist/bundle.esm.js

211 lines
5.4 KiB
JavaScript
Raw Normal View History

2023-04-13 16:31:30 +00:00
function abs(a) {
return (a >= 0) ? a : -a;
}
function bitLength(a) {
if (typeof a === 'number')
a = BigInt(a);
if (a === 1n) {
return 1;
}
let bits = 1;
do {
bits++;
} while ((a >>= 1n) > 1n);
return bits;
}
function eGcd(a, b) {
if (typeof a === 'number')
a = BigInt(a);
if (typeof b === 'number')
b = BigInt(b);
if (a <= 0n || b <= 0n)
throw new RangeError('a and b MUST be > 0');
let x = 0n;
let y = 1n;
let u = 1n;
let v = 0n;
while (a !== 0n) {
const q = b / a;
const r = b % a;
const m = x - (u * q);
const n = y - (v * q);
b = a;
a = r;
x = u;
y = v;
u = m;
v = n;
}
return {
g: b,
x,
y
};
}
function toZn(a, n) {
if (typeof a === 'number')
a = BigInt(a);
if (typeof n === 'number')
n = BigInt(n);
if (n <= 0n) {
throw new RangeError('n must be > 0');
}
const aZn = a % n;
return (aZn < 0n) ? aZn + n : aZn;
}
function modInv(a, n) {
const egcd = eGcd(toZn(a, n), n);
if (egcd.g !== 1n) {
throw new RangeError(`${a.toString()} does not have inverse modulo ${n.toString()}`);
}
else {
return toZn(egcd.x, n);
}
}
function crt(remainders, modulos, modulo) {
if (remainders.length !== modulos.length) {
throw new RangeError('The remainders and modulos arrays should have the same length');
}
const product = modulo ?? modulos.reduce((acc, val) => acc * val, 1n);
return modulos.reduce((sum, mod, index) => {
const partialProduct = product / mod;
const inverse = modInv(partialProduct, mod);
const toAdd = ((partialProduct * inverse) % product * remainders[index]) % product;
return toZn(sum + toAdd, product);
}, 0n);
}
2023-04-13 16:31:30 +00:00
function gcd(a, b) {
let aAbs = (typeof a === 'number') ? BigInt(abs(a)) : abs(a);
let bAbs = (typeof b === 'number') ? BigInt(abs(b)) : abs(b);
if (aAbs === 0n) {
return bAbs;
}
else if (bAbs === 0n) {
return aAbs;
}
let shift = 0n;
while (((aAbs | bAbs) & 1n) === 0n) {
aAbs >>= 1n;
bAbs >>= 1n;
shift++;
}
while ((aAbs & 1n) === 0n)
aAbs >>= 1n;
do {
while ((bAbs & 1n) === 0n)
bAbs >>= 1n;
if (aAbs > bAbs) {
const x = aAbs;
aAbs = bAbs;
bAbs = x;
}
bAbs -= aAbs;
} while (bAbs !== 0n);
return aAbs << shift;
}
function lcm(a, b) {
if (typeof a === 'number')
a = BigInt(a);
if (typeof b === 'number')
b = BigInt(b);
if (a === 0n && b === 0n)
return BigInt(0);
return abs((a / gcd(a, b)) * b);
}
function max(a, b) {
return (a >= b) ? a : b;
}
function min(a, b) {
return (a >= b) ? b : a;
}
function modAdd(addends, n) {
const mod = BigInt(n);
const as = addends.map(a => BigInt(a) % mod);
return toZn(as.reduce((sum, a) => sum + a % mod, 0n), mod);
2023-04-13 16:31:30 +00:00
}
function modMultiply(factors, n) {
const mod = BigInt(n);
const as = factors.map(a => BigInt(a) % mod);
return toZn(as.reduce((prod, a) => prod * a % mod, 1n), mod);
}
function phi(primeFactorization) {
return primeFactorization.map(v => (v[0] ** (v[1] - 1n)) * (v[0] - 1n)).reduce((prev, curr) => {
return curr * prev;
}, 1n);
2023-04-13 16:31:30 +00:00
}
function modPow(b, e, n, primeFactorization) {
2023-04-13 16:31:30 +00:00
if (typeof b === 'number')
b = BigInt(b);
if (typeof e === 'number')
e = BigInt(e);
if (typeof n === 'number')
n = BigInt(n);
if (n <= 0n) {
throw new RangeError('n must be > 0');
}
else if (n === 1n) {
return 0n;
}
b = toZn(b, n);
if (e < 0n) {
return modInv(modPow(b, abs(e), n, primeFactorization), n);
}
if (primeFactorization !== undefined) {
return modPowWithFactorization(b, e, n, primePowerArguments(primeFactorization));
2023-04-13 16:31:30 +00:00
}
let r = 1n;
while (e > 0) {
if ((e % 2n) === 1n) {
r = r * b % n;
}
e = e / 2n;
b = b ** 2n % n;
}
return r;
}
function primePowerArguments(primeFactors) {
const primePowers = {};
primeFactors.forEach((primeFactor) => {
if (typeof primeFactor === 'bigint' || typeof primeFactor === 'number') {
const key = String(primeFactor);
if (primePowers[key] === undefined) {
primePowers[key] = { p: BigInt(primeFactor), k: 1n };
}
else {
primePowers[key].k += 1n;
}
}
else {
const key = String(primeFactor[0]);
if (primePowers[key] === undefined) {
primePowers[key] = { p: BigInt(primeFactor[0]), k: BigInt(primeFactor[1]) };
}
else {
primePowers[key].k += BigInt(primeFactor[1]);
}
}
});
return Object.values(primePowers).map(val => [val.p, val.k]);
}
function modPowWithFactorization(b, e, n, primeFactorization) {
const mods = primeFactorization.map(v => v[0] ** v[1]);
const phis = primeFactorization.map(v => phi([v]));
const remainders = phis.map((phi, i) => modPow(b, e % phi, mods[i]));
return crt(remainders, mods, n);
}
2023-04-13 16:31:30 +00:00
export { abs, bitLength, crt, eGcd, gcd, lcm, max, min, modAdd, modInv, modMultiply, modPow, phi, toZn };