is a quadratic residue modulo an odd prime if is solvable. Euler’s criterion: ( residue, non-residue, if ); exactly nonzero residues exist. Roots come from Tonelli–Shanks or Cipolla, lift to by Hensel, combine over composite moduli by CRT. Related Diophantine equations: (Cornacchia), sums of two squares.
| Task | Method | Cost |
|---|---|---|
| is a residue mod prime | Euler’s criterion / Jacobi symbol | |
| Jacobi for odd | reciprocity, like Euclid | |
| Tonelli–Shanks () or Cipolla () | — | |
| Hensel lifting | ||
| roots mod each prime power + CRT ( combinations) | — | |
| Cornacchia (Euclid on ) | ||
| , count | factor; | factoring |
int jacobi(ll a, ll n) { // n odd > 0; Legendre symbol when n is prime
a %= n; if (a < 0) a += n; int t = 1;
while (a) {
while (a % 2 == 0) { a /= 2; if (n % 8 == 3 || n % 8 == 5) t = -t; }
swap(a, n); if (a % 4 == 3 && n % 4 == 3) t = -t;
a %= n;
}
return n == 1 ? t : 0;
}
ll sqrtMod(ll a, ll p) { // Tonelli-Shanks: some x with x^2 = a (mod p), -1 if none; p prime
a %= p; if (a < 0) a += p;
if (a == 0 || p == 2) return a;
if (power(a, (p - 1) / 2, p) != 1) return -1;
if (p % 4 == 3) return power(a, (p + 1) / 4, p);
ll q = p - 1; int s = 0; while (q % 2 == 0) q /= 2, s++;
ll z = 2; while (power(z, (p - 1) / 2, p) != p - 1) z++;
ll c = power(z, q, p), x = power(a, (q + 1) / 2, p), t = power(a, q, p); int m = s;
while (t != 1) {
int i = 0; ll tt = t; while (tt != 1) tt = (i128)tt * tt % p, i++;
ll b = c; for (int j = 0; j < m - i - 1; j++) b = (i128)b * b % p;
x = (i128)x * b % p; c = (i128)b * b % p; t = (i128)t * c % p; m = i;
}
return x;
}
ll cipolla(ll a, ll p) { // same contract, O(log p) multiplications in F_{p^2}
a %= p; if (a < 0) a += p;
if (a == 0 || p == 2) return a;
if (power(a, (p - 1) / 2, p) != 1) return -1;
ll r = 0, w = 0; mt19937_64 rng(7);
do { r = rng() % p; w = ((i128)r * r - a + p) % p; } while (power(w, (p - 1) / 2, p) != p - 1);
auto mul = [&](pair<ll, ll> x, pair<ll, ll> y) { return pair<ll, ll>{(ll)(((i128)x.first * y.first + (i128)x.second * y.second % p * w) % p), (ll)(((i128)x.first * y.second + (i128)x.second * y.first) % p)}; };
pair<ll, ll> res{1, 0}, b{r, 1};
for (ll e = (p + 1) / 2; e; e >>= 1, b = mul(b, b)) if (e & 1) res = mul(res, b);
return res.first; // (r + sqrt(w))^{(p+1)/2} lies in F_p
}
ll sqrtModPrimePower(ll a, ll p, int k) { // odd p, gcd(a, p) = 1: x^2 = a (mod p^k), -1 if none
ll x = sqrtMod(a % p, p); if (x < 0) return -1;
ll pk = p;
for (int i = 1; i < k; i++) { // x <- x - (x^2 - a) / (2x) mod p^{i+1}
pk *= p; ll am = ((a % pk) + pk) % pk;
ll f = ((i128)x * x - am) % pk; if (f < 0) f += pk;
x = (x - (i128)f * invMod(2 * x % pk, pk)) % pk; if (x < 0) x += pk;
}
return x;
}
pair<ll, ll> cornacchia(ll d, ll p) { // x^2 + d y^2 = p, p prime, 0 < d < p; {-1, -1} if none
ll r = sqrtMod(p - d % p, p); if (r < 0) return {-1, -1};
if (2 * r < p) r = p - r; // take the root > p / 2
ll a = p, b = r, lim = (ll)sqrtl(p); while (lim * lim > p) lim--;
while (b > lim) { ll t = a % b; a = b; b = t; }
ll rest = p - b * b; if (rest % d) return {-1, -1};
ll y = (ll)sqrtl(rest / d); while (y * y > rest / d) y--; while ((y + 1) * (y + 1) <= rest / d) y++;
if (y * y * d != rest) return {-1, -1};
return {b, y};
}Sums of two squares in full (all representations of , and ), from the library:
pair<i64, i64> primeTwoSquares(i64 p) {
if (p == 2) return {1, 1};
auto mulmod = [&](i64 a, i64 b) { return (i64)((i128)a * b % p); };
auto pw = [&](i64 b, i64 e) {
i64 r = 1;
for (b %= p; e; e >>= 1, b = mulmod(b, b)) {
if (e & 1) r = mulmod(r, b);
}
return r;
};
i64 x = 0;
for (i64 c = 2;; c++) {
if (pw(c, (p - 1) / 2) == p - 1) {
x = pw(c, (p - 1) / 4);
break;
}
}
i64 a = p, b = x;
i64 lim = sqrtl((long double)p);
while (b > lim) {
i64 t = a % b;
a = b, b = t;
}
i64 c = (i64)sqrtl((long double)(p - b * b));
while (c * c > p - b * b) c--;
while ((c + 1) * (c + 1) <= p - b * b) c++;
return {b, c};
}
vector<pair<i64, i64>> twoSquares(i64 n) {
vector<pair<i64, i64>> res;
if (n < 0) return res;
for (i64 x = 0; x * x <= n; x++) {
i64 rest = n - x * x;
i64 y = sqrtl((long double)rest);
while (y * y > rest) y--;
while ((y + 1) * (y + 1) <= rest) y++;
if (y * y == rest) res.push_back({x, y});
}
return res;
}
i64 r2(i64 n) {
if (n == 0) return 1;
i64 d1 = 0, d3 = 0;
auto count = [&](i64 e) {
if (e % 4 == 1) d1++;
else if (e % 4 == 3) d3++;
};
for (i64 d = 1; d * d <= n; d++) {
if (n % d) continue;
count(d);
if (d != n / d) count(n / d);
}
return 4 * (d1 - d3);
}| Fact | Statement |
|---|---|
| Euler’s criterion | |
| , as residues | is a QR iff ; iff |
| quadratic reciprocity | |
| number of roots of (odd ) | 0 or 2; modulo : product over prime powers ( has up to 4) |
| sum of two squares | is one iff every prime has even exponent; |
| Fermat | prime iff or |
Proof: Euler's criterion and the Jacobi algorithm
With a primitive root , is a square iff is even, and is iff is even, else the unique element of order 2, ; half of the exponents are even. The Jacobi symbol is multiplicative in both arguments; the loop uses (the cases ) and reciprocity for odd coprime to swap the arguments, reducing like Euclid; a common factor ends with and symbol 0.
Proof: Tonelli–Shanks and Cipolla
Tonelli–Shanks: write . Invariants: , has order , has order with . Initially , (order dividing since is a residue), (order exactly for a non-residue ). Multiplying by and by (order ) keeps and makes the order of drop below ; with , the invariants hold. When , . At most rounds of squarings. : . Cipolla: with a non-residue, is a field where (Frobenius, ). So , and squares to ; since has a root in and roots are unique up to sign in the field, . A random gives a non-residue with probability about .
Proof: Hensel lifting and Cornacchia
Hensel: if and , set ; then , in particular modulo , and the lift is unique (the derivative is invertible). Cornacchia: if with , then , and running Euclid on with , , stops at the first remainder , which is ; this follows from the continued-fraction characterisation of the convergents of (the pair appears as a convergent because for the corresponding ). The final check verifies that is a perfect square; if not, no primitive representation exists.