// C++ program to implement Shanks Tonelli algorithm for
// finding Modular Square Roots
#include <bits/stdc++.h>
using namespace std;
// utility function to find pow(base, exponent) % modulus
int pow(int base, int exponent, int modulus)
{
int result = 1;
base = base % modulus;
while (exponent > 0)
{
if (exponent % 2 == 1)
result = (result * base)% modulus;
exponent = exponent >> 1;
base = (base * base) % modulus;
}
return result;
}
// utility function to find gcd
int gcd(int a, int b)
{
if (b == 0)
return a;
else
return gcd(b, a % b);
}
// Returns k such that b^k = 1 (mod p)
int order(int p, int b)
{
if (gcd(p, b) != 1)
{
printf("p and b are not co-prime.\n");
return -1;
}
// Initializing k with first odd prime number
int k = 3;
while (1)
{
if (pow(b, k, p) == 1)
return k;
k++;
}
}
// function return p - 1 (= x argument) as x * 2^e,
// where x will be odd sending e as reference because
// updation is needed in actual e
int convertx2e(int x, int& e)
{
e = 0;
while (x % 2 == 0)
{
x /= 2;
e++;
}
return x;
}
// Main function for finding the modular square root
int STonelli(int n, int p)
{
// a and p should be coprime for finding the modular
// square root
if (gcd(n, p) != 1)
{
printf("a and p are not coprime\n");
return -1;
}
// If below expression return (p - 1) then modular
// square root is not possible
if (pow(n, (p - 1) / 2, p) == (p - 1))
{
printf("no sqrt possible\n");
return -1;
}
// expressing p - 1, in terms of s * 2^e, where s
// is odd number
int s, e;
s = convertx2e(p - 1, e);
// finding smallest q such that q ^ ((p - 1) / 2)
// (mod p) = p - 1
int q;
for (q = 2; ; q++)
{
// q - 1 is in place of (-1 % p)
if (pow(q, (p - 1) / 2, p) == (p - 1))
break;
}
// Initializing variable x, b and g
int x = pow(n, (s + 1) / 2, p);
int b = pow(n, s, p);
int g = pow(q, s, p);
int r = e;
// keep looping until b become 1 or m becomes 0
while (1)
{
int m;
for (m = 0; m < r; m++)
{
if (order(p, b) == -1)
return -1;
// finding m such that b^ (2^m) = 1
if (order(p, b) == pow(2, m))
break;
}
if (m == 0)
return x;
// updating value of x, g and b according to
// algorithm
x = (x * pow(g, pow(2, r - m - 1), p)) % p;
g = pow(g, pow(2, r - m), p);
b = (b * g) % p;
if (b == 1)
return x;
r = m;
}
}
// driver program to test above function
int main()
{
int n = 2;
// p should be prime
int p = 113;
int x = STonelli(n, p);
if (x == -1)
printf("Modular square root is not exist\n");
else
printf("Modular square root of %d and %d is %d\n",
n, p, x);
}