📜  在Modulo p下找到平方根|集合2(Shanks Tonelli算法)

📅  最后修改于: 2021-04-29 10:51:15             🧑  作者: Mango

给定数字“ n”和质数“ p”,请在模p下找到n的平方根(如果存在)。
例子:

Input: n = 2, p = 113
Output: 62
62^2 = 3844  and  3844 % 113 = 2

Input:  n = 2, p = 7
Output: 3 or 4
3 and 4 both are square roots of 2 under modulo
7 because (3*3) % 7 = 2 and (4*4) % 7 = 2

Input:  n = 2, p = 5
Output: Square root doesn't exist

我们讨论了欧拉准则来检查平方根是否存在。我们还讨论了仅当p的形式为4 * i + 3时有效的解决方案
在本文中,将讨论Shank Tonelli的算法,该算法适用于所有类型的输入。
使用Shank Tonelli算法查找模块化平方根的算法步骤:
1)计算n ^((p – 1)/ 2)(mod p),必须为1或p-1,如果为p-1,则模平方根不可能。
2)然后,对于某些整数s和e,将p-1写为(s * 2 ^ e),其中s必须是奇数,并且s和e都应为正。
3)然后找到一个数字q,使得q ^((p – 1)/ 2)(mod p)= -1
4)通过以下值初始化变量x,b,g和r

x = n ^ ((s + 1) / 2 (first guess of square root)
   b = n ^ s                
   g = q ^ s
   r = e   (exponent e will decrease after each updation) 

5)现在循环直到m> 0并更新x的值,这将是我们的最终答案。

Find least integer m such that b^(2^m) = 1(mod p)  and  0 <= m <= r – 1 
   If m = 0, then we found correct answer and return x as result
   Else update x, b, g, r as below
       x = x * g ^ (2 ^ (r – m - 1))
       b = b * g ^(2 ^ (r - m))
       g = g ^ (2 ^ (r - m))
       r = m 

因此,如果m变为0或b变为1,我们将终止并打印结果。此循环保证终止,因为更新后每次m的值都会减小。
以下是上述算法的实现。

C++
// C++ program to implement Shanks Tonelli algorithm for
// finding Modular  Square Roots
#include 
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);
}


Java
// Java program to implement Shanks
// Tonelli algorithm for finding
// Modular Square Roots
class GFG
{
    static int z = 0;
     
// utility function to find
// pow(base, exponent) % modulus
static int pow1(int base1,
    int exponent, int modulus)
{
    int result = 1;
    base1 = base1 % modulus;
    while (exponent > 0)
    {
        if (exponent % 2 == 1)
            result = (result * base1) % modulus;
        exponent = exponent >> 1;
        base1 = (base1 * base1) % modulus;
    }
    return result;
}
 
// utility function to find gcd
static 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)
static int order(int p, int b)
{
    if (gcd(p, b) != 1)
    {
        System.out.println("p and b are" +
                            "not co-prime.");
        return -1;
    }
 
    // Initializing k with first
    // odd prime number
    int k = 3;
    while (true)
    {
        if (pow1(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
static int convertx2e(int x)
{
    z = 0;
    while (x % 2 == 0)
    {
        x /= 2;
        z++;
    }
    return x;
}
 
// Main function for finding
// the modular square root
static int STonelli(int n, int p)
{
    // a and p should be coprime for 
    // finding the modular square root
    if (gcd(n, p) != 1)
    {
        System.out.println("a and p are not coprime");
        return -1;
    }
 
    // If below expression return (p - 1) then modular
    // square root is not possible
    if (pow1(n, (p - 1) / 2, p) == (p - 1))
    {
        System.out.println("no sqrt possible");
        return -1;
    }
 
    // expressing p - 1, in terms of 
    // s * 2^e, where s is odd number
    int s, e;
    s = convertx2e(p - 1);
    e = z;
 
    // 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 (pow1(q, (p - 1) / 2, p) == (p - 1))
            break;
    }
 
    // Initializing variable x, b and g
    int x = pow1(n, (s + 1) / 2, p);
    int b = pow1(n, s, p);
    int g = pow1(q, s, p);
 
    int r = e;
 
    // keep looping until b
    // become 1 or m becomes 0
    while (true)
    {
        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) == Math.pow(2, m))
                break;
        }
        if (m == 0)
            return x;
 
        // updating value of x, g and b
        // according to algorithm
        x = (x * pow1(g, (int)Math.pow(2,
                            r - m - 1), p)) % p;
        g = pow1(g, (int)Math.pow(2, r - m), p);
        b = (b * g) % p;
 
        if (b == 1)
            return x;
        r = m;
    }
}
 
// Driver code
public static void main (String[] args)
{
 
    int n = 2;
 
    // p should be prime
    int p = 113;
 
    int x = STonelli(n, p);
 
    if (x == -1)
        System.out.println("Modular square" +
                        "root is not exist\n");
    else
        System.out.println("Modular square root of " +
                            n + " and " + p + " is " +
                            x + "\n");
}
}
 
// This code is contributed by mits


Python3
# Python3 program to implement Shanks Tonelli
# algorithm for finding Modular Square Roots
 
# utility function to find pow(base,
# exponent) % modulus
def pow1(base, exponent, modulus):
 
    result = 1;
    base = base % modulus;
    while (exponent > 0):
        if (exponent % 2 == 1):
            result = (result * base) % modulus;
        exponent = int(exponent) >> 1;
        base = (base * base) % modulus;
 
    return result;
 
# utility function to find gcd
def gcd(a, b):
    if (b == 0):
        return a;
    else:
        return gcd(b, a % b);
 
# Returns k such that b^k = 1 (mod p)
def order(p, b):
 
    if (gcd(p, b) != 1):
        print("p and b are not co-prime.\n");
        return -1;
 
    # Initializing k with first
    # odd prime number
    k = 3;
    while (True):
        if (pow1(b, k, p) == 1):
            return k;
        k += 1;
 
# 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
def convertx2e(x):
    z = 0;
    while (x % 2 == 0):
        x = x / 2;
        z += 1;
         
    return [x, z];
 
# Main function for finding the
# modular square root
def STonelli(n, p):
 
    # a and p should be coprime for
    # finding the modular square root
    if (gcd(n, p) != 1):
        print("a and p are not coprime\n");
        return -1;
 
    # If below expression return (p - 1) then
    # modular square root is not possible
    if (pow1(n, (p - 1) / 2, p) == (p - 1)):
        print("no sqrt possible\n");
        return -1;
 
    # expressing p - 1, in terms of s * 2^e,
    # where s is odd number
    ar = convertx2e(p - 1);
    s = ar[0];
    e = ar[1];
 
    # finding smallest q such that
    # q ^ ((p - 1) / 2) (mod p) = p - 1
    q = 2;
    while (True):
         
        # q - 1 is in place of (-1 % p)
        if (pow1(q, (p - 1) / 2, p) == (p - 1)):
            break;
        q += 1;
 
    # Initializing variable x, b and g
    x = pow1(n, (s + 1) / 2, p);
    b = pow1(n, s, p);
    g = pow1(q, s, p);
 
    r = e;
 
    # keep looping until b become
    # 1 or m becomes 0
    while (True):
        m = 0;
        while (m < r):
            if (order(p, b) == -1):
                return -1;
 
            # finding m such that b^ (2^m) = 1
            if (order(p, b) == pow(2, m)):
                break;
            m += 1;
 
        if (m == 0):
            return x;
 
        # updating value of x, g and b
        # according to algorithm
        x = (x * pow1(g, pow(2, r - m - 1), p)) % p;
        g = pow1(g, pow(2, r - m), p);
        b = (b * g) % p;
 
        if (b == 1):
            return x;
        r = m;
 
# Driver Code
n = 2;
 
# p should be prime
p = 113;
 
x = STonelli(n, p);
 
if (x == -1):
    print("Modular square root is not exist\n");
else:
    print("Modular square root of", n,
          "and", p, "is", x);
         
# This code is contributed by mits


C#
// C# program to implement Shanks
// Tonelli algorithm for finding
// Modular Square Roots
using System;
 
class GFG
{
     
static int z=0;
     
// utility function to find
// pow(base, exponent) % modulus
static int pow1(int base1,
        int exponent, int modulus)
{
    int result = 1;
    base1 = base1 % modulus;
    while (exponent > 0)
    {
        if (exponent % 2 == 1)
            result = (result * base1) % modulus;
        exponent = exponent >> 1;
        base1 = (base1 * base1) % modulus;
    }
    return result;
}
 
// utility function to find gcd
static 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)
static int order(int p, int b)
{
    if (gcd(p, b) != 1)
    {
        Console.WriteLine("p and b are" +
                            "not co-prime.");
        return -1;
    }
 
    // Initializing k with
    // first odd prime number
    int k = 3;
    while (true)
    {
        if (pow1(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
static int convertx2e(int x)
{
    z = 0;
    while (x % 2 == 0)
    {
        x /= 2;
        z++;
    }
    return x;
}
 
// Main function for finding
// the modular square root
static int STonelli(int n, int p)
{
    // a and p should be coprime for
    // finding the modular square root
    if (gcd(n, p) != 1)
    {
        Console.WriteLine("a and p are not coprime");
        return -1;
    }
 
    // If below expression return (p - 1) then
    // modular square root is not possible
    if (pow1(n, (p - 1) / 2, p) == (p - 1))
    {
        Console.WriteLine("no sqrt possible");
        return -1;
    }
 
    // expressing p - 1, in terms of s * 2^e,
    //  where s is odd number
    int s, e;
    s = convertx2e(p - 1);
    e=z;
 
    // 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 (pow1(q, (p - 1) / 2, p) == (p - 1))
            break;
    }
 
    // Initializing variable x, b and g
    int x = pow1(n, (s + 1) / 2, p);
    int b = pow1(n, s, p);
    int g = pow1(q, s, p);
 
    int r = e;
 
    // keep looping until b become
    // 1 or m becomes 0
    while (true)
    {
        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) == Math.Pow(2, m))
                break;
        }
        if (m == 0)
            return x;
 
        // updating value of x, g and b 
        // according to algorithm
        x = (x * pow1(g, (int)Math.Pow(2, r - m - 1), p)) % p;
        g = pow1(g, (int)Math.Pow(2, r - m), p);
        b = (b * g) % p;
 
        if (b == 1)
            return x;
        r = m;
    }
}
 
// Driver code
static void Main()
{
    int n = 2;
 
    // p should be prime
    int p = 113;
 
    int x = STonelli(n, p);
 
    if (x == -1)
        Console.WriteLine("Modular square root" +
                            "is not exist\n");
    else
        Console.WriteLine("Modular square root of" +
                        "{0} and {1} is {2}\n", n, p, x);
}
}
 
// This code is contributed by mits


PHP
 0)
    {
        if ($exponent % 2 == 1)
        $result = ($result * $base) % $modulus;
        $exponent = $exponent >> 1;
        $base = ($base * $base) % $modulus;
    }
    return $result;
}
 
// utility function to find gcd
function gcd($a, $b)
{
    if ($b == 0)
        return $a;
    else
        return gcd($b, $a % $b);
}
 
// Returns k such that b^k = 1 (mod p)
function order($p, $b)
{
    if (gcd($p, $b) != 1)
    {
        print("p and b are not co-prime.\n");
        return -1;
    }
 
    // Initializing k with first
    // odd prime number
    $k = 3;
    while (1)
    {
        if (pow1($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
function convertx2e($x, &$e)
{
    $e = 0;
    while ($x % 2 == 0)
    {
        $x = (int)($x / 2);
        $e++;
    }
    return $x;
}
 
// Main function for finding the
// modular square root
function STonelli($n, $p)
{
    // a and p should be coprime for
    // finding the modular square root
    if (gcd($n, $p) != 1)
    {
        print("a and p are not coprime\n");
        return -1;
    }
 
    // If below expression return (p - 1) then
    // modular square root is not possible
    if (pow1($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
    $e = 0;
    $s = convertx2e($p - 1, $e);
 
    // finding smallest q such that
    // q ^ ((p - 1) / 2) (mod p) = p - 1
    $q = 2;
    for (; ; $q++)
    {
        // q - 1 is in place of (-1 % p)
        if (pow1($q, ($p - 1) / 2, $p) == ($p - 1))
            break;
    }
 
    // Initializing variable x, b and g
    $x = pow1($n, ($s + 1) / 2, $p);
    $b = pow1($n, $s, $p);
    $g = pow1($q, $s, $p);
 
    $r = $e;
 
    // keep looping until b become
    // 1 or m becomes 0
    while (1)
    {
        $m = 0;
        for (; $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 * pow1($g, pow(2, $r - $m - 1), $p)) % $p;
        $g = pow1($g, pow(2, $r - $m), $p);
        $b = ($b * $g) % $p;
 
        if ($b == 1)
            return $x;
        $r = $m;
    }
}
 
// Driver Code
$n = 2;
 
// p should be prime
$p = 113;
 
$x = STonelli($n, $p);
 
if ($x == -1)
    print("Modular square root is not exist\n");
else
    print("Modular square root of " .
          "$n and $p is $x\n");
     
// This code is contributed by mits
?>


Javascript


输出 :

Modular square root of 2 and 113 is 62