* Tonelli–Shanks: a single square root of `a` modulo an ODD PRIME `p`, in * `[0, p)`, or `null` if `a` is a quadratic non-residue. The other root is * `p − r`.
(a: bigint, p: bigint)
| 425 | * `p − r`. |
| 426 | */ |
| 427 | function sqrtModPrime(a: bigint, p: bigint): bigint | null { |
| 428 | a = ((a % p) + p) % p; |
| 429 | if (a === 0n) return 0n; |
| 430 | if (p === 2n) return a & 1n; |
| 431 | // Euler's criterion. |
| 432 | if (modPow(a, (p - 1n) / 2n, p) !== 1n) return null; |
| 433 | if (p % 4n === 3n) return modPow(a, (p + 1n) / 4n, p); |
| 434 | |
| 435 | // Factor p − 1 = q·2^s with q odd. |
| 436 | let q = p - 1n; |
| 437 | let s = 0n; |
| 438 | while (q % 2n === 0n) { |
| 439 | q /= 2n; |
| 440 | s += 1n; |
| 441 | } |
| 442 | // Find a quadratic non-residue z. |
| 443 | let z = 2n; |
| 444 | while (modPow(z, (p - 1n) / 2n, p) !== p - 1n) z += 1n; |
| 445 | |
| 446 | let m = s; |
| 447 | let cc = modPow(z, q, p); |
| 448 | let t = modPow(a, q, p); |
| 449 | let r = modPow(a, (q + 1n) / 2n, p); |
| 450 | let guard = 0; |
| 451 | while (t !== 1n) { |
| 452 | if (++guard > MAX_ITERATIONS) throw new DiophantineBudgetError(); |
| 453 | // Least i, 0 < i < m, with t^(2^i) = 1. |
| 454 | let i = 0n; |
| 455 | let t2 = t; |
| 456 | while (t2 !== 1n) { |
| 457 | t2 = (t2 * t2) % p; |
| 458 | i += 1n; |
| 459 | if (i === m) return null; // should not happen for a QR |
| 460 | } |
| 461 | let b = cc; |
| 462 | for (let j = 0n; j < m - i - 1n; j++) b = (b * b) % p; |
| 463 | m = i; |
| 464 | cc = (b * b) % p; |
| 465 | t = (t * cc) % p; |
| 466 | r = (r * b) % p; |
| 467 | } |
| 468 | return r; |
| 469 | } |
| 470 | |
| 471 | /** |
| 472 | * All roots of `x² ≡ a (mod pᵏ)` for an ODD prime `p`, `k ≥ 1`, sorted |
no test coverage detected