114 lines
2.9 KiB
JavaScript
114 lines
2.9 KiB
JavaScript
class TonelliShanks {
|
|
static ts(n, p) {
|
|
// Convert to BigInt if not already
|
|
n = typeof n === 'bigint' ? n : BigInt(n);
|
|
p = typeof p === 'bigint' ? p : BigInt(p);
|
|
|
|
const ZERO = BigInt(0);
|
|
const ONE = BigInt(1);
|
|
const TWO = BigInt(2);
|
|
|
|
// Helper function for modular exponentiation
|
|
const powModP = (a, e) => {
|
|
let result = BigInt(1);
|
|
a = a % p;
|
|
while (e > ZERO) {
|
|
if (e % TWO === ONE) {
|
|
result = (result * a) % p;
|
|
}
|
|
e = e / TWO;
|
|
a = (a * a) % p;
|
|
}
|
|
return result;
|
|
};
|
|
|
|
// Legendre symbol calculation
|
|
const ls = (a) => powModP(a, (p - ONE) / TWO);
|
|
|
|
if (ls(n) !== ONE) return { root1: ZERO, root2: ZERO, exists: false };
|
|
|
|
let q = p - ONE;
|
|
let ss = ZERO;
|
|
while (q % TWO === ZERO) {
|
|
ss += ONE;
|
|
q /= TWO;
|
|
}
|
|
|
|
if (ss === ONE) {
|
|
const r1 = powModP(n, (p + ONE) / BigInt(4));
|
|
return { root1: r1, root2: p - r1, exists: true };
|
|
}
|
|
|
|
let z = TWO;
|
|
while (ls(z) !== p - ONE) z += ONE;
|
|
|
|
let c = powModP(z, q);
|
|
let r = powModP(n, (q + ONE) / TWO);
|
|
let t = powModP(n, q);
|
|
let m = ss;
|
|
|
|
while (true) {
|
|
if (t === ONE) return { root1: r, root2: p - r, exists: true };
|
|
|
|
let i = ZERO;
|
|
let zz = t;
|
|
while (zz !== ONE && i < m - ONE) {
|
|
zz = (zz * zz) % p;
|
|
i += ONE;
|
|
}
|
|
|
|
let b = c;
|
|
let e = m - i - ONE;
|
|
while (e > ZERO) {
|
|
b = (b * b) % p;
|
|
e -= ONE;
|
|
}
|
|
|
|
r = (r * b) % p;
|
|
c = (b * b) % p;
|
|
t = (t * c) % p;
|
|
m = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Main function
|
|
function main() {
|
|
const pairs = [
|
|
[10n, 13n],
|
|
[56n, 101n],
|
|
[1030n, 10009n],
|
|
[1032n, 10009n],
|
|
[44402n, 100049n],
|
|
[665820697n, 1000000009n],
|
|
[881398088036n, 1000000000039n]
|
|
];
|
|
|
|
for (const [n, p] of pairs) {
|
|
const sol = TonelliShanks.ts(n, p);
|
|
console.log(`n = ${n}`);
|
|
console.log(`p = ${p}`);
|
|
if (sol.exists) {
|
|
console.log(`root1 = ${sol.root1}`);
|
|
console.log(`root2 = ${sol.root2}`);
|
|
} else {
|
|
console.log("No solution exists");
|
|
}
|
|
console.log();
|
|
}
|
|
|
|
const bn = 41660815127637347468140745042827704103445750172002n;
|
|
const bp = BigInt(10) ** 50n + 577n;
|
|
const sol = TonelliShanks.ts(bn, bp);
|
|
console.log(`n = ${bn}`);
|
|
console.log(`p = ${bp}`);
|
|
if (sol.exists) {
|
|
console.log(`root1 = ${sol.root1}`);
|
|
console.log(`root2 = ${sol.root2}`);
|
|
} else {
|
|
console.log("No solution exists");
|
|
}
|
|
}
|
|
|
|
main();
|