📜  离散对数(找到一个整数k,以使a ^ k为模b的全等)

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

给定三个整数a,b和m。找出一个整数k使得a^k \equiv b \pmod m其中a和m是相对质数。如果任何k都不可能满足此关系,则打印-1。

例子:

Input: 2 3 5
Output: 3
Explanation:
a = 2, b = 3, m = 5
The value which satisfies the above equation
is 3, because 
=> 23 = 2 * 2 * 2 = 8
=> 23 (mod 5) = 8 (mod 5) 
=> 3
which is equal to b i.e., 3.

Input: 3 7 11
Output: -1

幼稚的方法是运行一个从0到m的循环以覆盖k的所有可能值,并检查上述关系是否满足k的值。如果k的所有值均用尽,则打印-1。 Thuis方法的时间复杂度为O(m)

一种有效的方法是通过在中间的技巧中使用Meet来使用婴儿步,巨型步算法。

婴儿步巨步算法

给定一个阶次为’m’的循环群G,该群的生成器’a’和一个群元素’b’,问题是要找到一个整数’k’,使得a^k \equiv b \pmod m
因此,我们要做的(根据中间技巧中的Meet)是将问题分为以下两个部分: \sqrt{m}分别解决它们,然后找到碰撞。

现在根据婴儿步长巨步算法,我们可以将“ k”写为k=i\cdot n - jn = \left\lceil \sqrt{m} \right\rceil0 \leq i < n0\leq j<n 。因此,我们有: \implies a^{i\cdot n - j} = b \pmod m\implies a^{i\cdot n} = a^{j}\cdot b \pmod m因此为了解决,我们预先计算a^{i\cdot n}对于不同的“ i”值。然后修复’b’并尝试上述同余关系的RHS中的’j’值。它使用LHS的预先计算的值进行测试,以查看是否满足任何’j’值。

让我们看看如何使用上述算法解决我们的问题:

首先我们要写k = i\cdot n - j , 在哪里n = \left\lceil \sqrt{m} \right\rceil显然,间隔[0,m)k的任何值都可以用这种形式表示,其中i \in [1, n)j \in [0, n)
替换上面的等式中的“ k”,我们得到:
\implies a^k = b \pmod m
\implies a^{i\cdot n - j} = b \pmod m
\implies a^{i\cdot n} = a^j\cdot b \pmod m

  1. 左右项只能取n个不同的值,例如i, j \in [0, n) 。因此,我们需要为相等的左或右部分生成所有这些术语,并将它们存储在数组或数据结构中,例如C / C++中的map / unordered_map或Java的Hashmap。
  2. 假设我们已经存储了所有LHS值。现在,遍历RHS上所有可能的条件以获取j的不同值,并检查哪个值满足LHS相等性。
  3. 如果上述步骤中j的任何候选值都不满足,则打印-1。
C++
// C++ program to calculate discrete logarithm
#include
using namespace std;
  
/* Iterative Function to calculate (x ^ y)%p in 
   O(log y) */
int powmod(int x, int y, int p)
{
    int res = 1;  // Initialize result
  
    x = x % p;  // Update x if it is more than or
                // equal to p
  
    while (y > 0)
    {
        // If y is odd, multiply x with result
        if (y & 1)
            res = (res*x) % p;
  
        // y must be even now
        y = y>>1; // y = y/2
        x = (x*x) % p;
    }
    return res;
}
  
// Function to calculate k for given a, b, m
int discreteLogarithm(int a, int b, int m) {
  
    int n = (int) sqrt (m) + 1;
  
    unordered_map value;
  
    // Store all values of a^(n*i) of LHS
    for (int i = n; i >= 1; --i)
        value[ powmod (a, i * n, m) ] = i;
  
    for (int j = 0; j < n; ++j)
    {
        // Calculate (a ^ j) * b and check
        // for collision
        int cur = (powmod (a, j, m) * b) % m;
  
        // If collision occurs i.e., LHS = RHS
        if (value[cur])
        {
            int ans = value[cur] * n - j;
            // Check whether ans lies below m or not
            if (ans < m)
                return ans;
        }
    }
    return -1;
}
  
// Driver code
int main()
{
    int a = 2, b = 3, m = 5;
    cout << discreteLogarithm(a, b, m) << endl;
  
    a = 3, b = 7, m = 11;
    cout << discreteLogarithm(a, b, m);
}


Java
// Java program to calculate discrete logarithm 
  
class GFG{
/* Iterative Function to calculate (x ^ y)%p in 
O(log y) */
static int powmod(int x, int y, int p) 
{ 
    int res = 1; // Initialize result 
  
    x = x % p; // Update x if it is more than or 
                // equal to p 
  
    while (y > 0) 
    { 
        // If y is odd, multiply x with result 
        if ((y & 1)>0) 
            res = (res*x) % p; 
  
        // y must be even now 
        y = y>>1; // y = y/2 
        x = (x*x) % p; 
    } 
    return res; 
} 
  
// Function to calculate k for given a, b, m 
static int discreteLogarithm(int a, int b, int m) { 
  
    int n = (int) (Math.sqrt (m) + 1); 
  
    int[] value=new int[m]; 
  
    // Store all values of a^(n*i) of LHS 
    for (int i = n; i >= 1; --i) 
        value[ powmod (a, i * n, m) ] = i; 
  
    for (int j = 0; j < n; ++j) 
    { 
        // Calculate (a ^ j) * b and check 
        // for collision 
        int cur = (powmod (a, j, m) * b) % m; 
  
        // If collision occurs i.e., LHS = RHS 
        if (value[cur]>0) 
        { 
            int ans = value[cur] * n - j; 
            // Check whether ans lies below m or not 
            if (ans < m) 
                return ans; 
        } 
    } 
    return -1; 
} 
  
// Driver code 
public static void main(String[] args) 
{ 
    int a = 2, b = 3, m = 5; 
    System.out.println(discreteLogarithm(a, b, m)); 
  
    a = 3;
    b = 7;
    m = 11; 
    System.out.println(discreteLogarithm(a, b, m)); 
} 
}
// This code is contributed by mits


Python3
# Python3 program to calculate 
# discrete logarithm 
import math;
  
# Iterative Function to calculate 
# (x ^ y)%p in O(log y) 
def powmod(x, y, p): 
  
    res = 1; # Initialize result 
  
    x = x % p; # Update x if it is more 
               # than or equal to p 
  
    while (y > 0): 
          
        # If y is odd, multiply x with result 
        if (y & 1): 
            res = (res * x) % p; 
  
        # y must be even now 
        y = y >> 1; # y = y/2 
        x = (x * x) % p; 
    return res; 
  
# Function to calculate k for given a, b, m 
def discreteLogarithm(a, b, m): 
    n = int(math.sqrt(m) + 1); 
  
    value = [0] * m; 
  
    # Store all values of a^(n*i) of LHS 
    for i in range(n, 0, -1): 
        value[ powmod (a, i * n, m) ] = i; 
  
    for j in range(n): 
          
        # Calculate (a ^ j) * b and check 
        # for collision 
        cur = (powmod (a, j, m) * b) % m; 
  
        # If collision occurs i.e., LHS = RHS 
        if (value[cur]): 
            ans = value[cur] * n - j; 
              
            # Check whether ans lies below m or not 
            if (ans < m): 
                return ans; 
      
    return -1; 
  
# Driver code 
a = 2; 
b = 3; 
m = 5; 
print(discreteLogarithm(a, b, m)); 
  
a = 3; 
b = 7; 
m = 11; 
print(discreteLogarithm(a, b, m)); 
  
# This code is contributed by mits


C#
// C# program to calculate discrete logarithm 
using System;
class GFG{
/* Iterative Function to calculate (x ^ y)%p in 
O(log y) */
static int powmod(int x, int y, int p) 
{ 
    int res = 1; // Initialize result 
  
    x = x % p; // Update x if it is more than or 
                // equal to p 
  
    while (y > 0) 
    { 
        // If y is odd, multiply x with result 
        if ((y & 1)>0) 
            res = (res*x) % p; 
  
        // y must be even now 
        y = y>>1; // y = y/2 
        x = (x*x) % p; 
    } 
    return res; 
} 
  
// Function to calculate k for given a, b, m 
static int discreteLogarithm(int a, int b, int m) { 
  
    int n = (int) (Math.Sqrt (m) + 1); 
  
    int[] value=new int[m]; 
  
    // Store all values of a^(n*i) of LHS 
    for (int i = n; i >= 1; --i) 
        value[ powmod (a, i * n, m) ] = i; 
  
    for (int j = 0; j < n; ++j) 
    { 
        // Calculate (a ^ j) * b and check 
        // for collision 
        int cur = (powmod (a, j, m) * b) % m; 
  
        // If collision occurs i.e., LHS = RHS 
        if (value[cur]>0) 
        { 
            int ans = value[cur] * n - j; 
            // Check whether ans lies below m or not 
            if (ans < m) 
                return ans; 
        } 
    } 
    return -1; 
} 
  
// Driver code 
static void Main() 
{ 
    int a = 2, b = 3, m = 5; 
    Console.WriteLine(discreteLogarithm(a, b, m)); 
  
    a = 3;
    b = 7;
    m = 11; 
    Console.WriteLine(discreteLogarithm(a, b, m)); 
} 
}
// This code is contributed by mits


PHP
 0)
    {
        // If y is odd, multiply x with result
        if ($y & 1)
            $res = ($res * $x) % $p;
  
        // y must be even now
        $y = $y >> 1; // y = y/2
        $x = ($x * $x) % $p;
    }
    return $res;
}
  
// Function to calculate k for given a, b, m
function discreteLogarithm($a, $b, $m) 
{
    $n = (int)sqrt($m) + 1;
  
    $value = array_fill(0, $m, NULL);
  
    // Store all values of a^(n*i) of LHS
    for ($i = $n; $i >= 1; --$i)
        $value[ powmod ($a, $i * $n, $m) ] = $i;
  
    for ($j = 0; $j < $n; ++$j)
    {
        // Calculate (a ^ j) * b and check
        // for collision
        $cur = (powmod ($a, $j, $m) * $b) % $m;
  
        // If collision occurs i.e., LHS = RHS
        if ($value[$cur])
        {
            $ans = $value[$cur] * $n - $j;
              
            // Check whether ans lies below m or not
            if ($ans < $m)
                return $ans;
        }
    }
    return -1;
}
  
// Driver code
$a = 2;
$b = 3;
$m = 5;
echo discreteLogarithm($a, $b, $m), "\n";
  
$a = 3;
$b = 7;
$m = 11;
echo discreteLogarithm($a, $b, $m), "\n";
  
// This code is contributed by ajit.
?>


C++
// C++ program to calculate discrete logarithm
#include
using namespace std;
  
int discreteLogarithm(int a, int b, int m) 
{
    int n = (int) sqrt (m) + 1;
  
    // Calculate a ^ n 
    int an = 1;
    for (int i = 0; i value;
  
    // Store all values of a^(n*i) of LHS
    for (int i = 1, cur = an; i<= n; ++i)
    {
        if (! value[ cur ])
            value[ cur ] = i;
        cur = (cur * an) % m;
    }
  
    for (int i = 0, cur = b; i<= n; ++i)
    {
        // Calculate (a ^ j) * b and check
        // for collision
        if (value[cur])
        {
            int ans = value[cur] * n - i;
            if (ans < m)
                return ans;
        }
        cur = (cur * a) % m;
    }
    return -1;
}
  
// Driver code
int main()
{
    int a = 2, b = 3, m = 5;
    cout << discreteLogarithm(a, b, m) << endl;
  
    a = 3, b = 7, m = 11;
    cout << discreteLogarithm(a, b, m);
}


Java
// Java program to calculate discrete logarithm 
  
class GFG
{
  
    static int discreteLogarithm(int a, int b, int m) 
    { 
        int n = (int) (Math.sqrt (m) + 1); 
  
        // Calculate a ^ n 
        int an = 1; 
        for (int i = 0; i < n; ++i) 
            an = (an * a) % m; 
  
        int[] value=new int[m]; 
  
        // Store all values of a^(n*i) of LHS 
        for (int i = 1, cur = an; i <= n; ++i) 
        { 
            if (value[ cur ] == 0) 
                value[ cur ] = i; 
            cur = (cur * an) % m; 
        } 
  
        for (int i = 0, cur = b; i <= n; ++i) 
        { 
            // Calculate (a ^ j) * b and check 
            // for collision 
            if (value[cur] > 0) 
            { 
                int ans = value[cur] * n - i; 
                if (ans < m) 
                    return ans; 
            } 
            cur = (cur * a) % m; 
        } 
        return -1; 
    } 
  
    // Driver code 
    public static void main(String[] args) 
    { 
        int a = 2, b = 3, m = 5; 
        System.out.println(discreteLogarithm(a, b, m)); 
        a = 3;
        b = 7;
        m = 11; 
        System.out.println(discreteLogarithm(a, b, m)); 
    } 
}
  
// This code is contributed by mits


Python3
# Python3 program to calculate 
# discrete logarithm
import math;
  
def discreteLogarithm(a, b, m): 
  
    n = int(math.sqrt (m) + 1);
  
    # Calculate a ^ n 
    an = 1;
    for i in range(n):
        an = (an * a) % m;
  
    value = [0] * m;
  
    # Store all values of a^(n*i) of LHS
    cur = an;
    for i in range(1, n + 1):
        if (value[ cur ] == 0):
            value[ cur ] = i;
        cur = (cur * an) % m;
      
    cur = b;
    for i in range(n + 1):
          
        # Calculate (a ^ j) * b and check
        # for collision
        if (value[cur] > 0):
            ans = value[cur] * n - i;
            if (ans < m):
                return ans;
        cur = (cur * a) % m;
  
    return -1;
  
# Driver code
a = 2;
b = 3;
m = 5;
print(discreteLogarithm(a, b, m));
  
a = 3;
b = 7;
m = 11;
print(discreteLogarithm(a, b, m));
  
# This code is contributed by mits


C#
// C# program to calculate discrete logarithm 
using System;
  
class GFG 
{
      
static int discreteLogarithm(int a, int b, int m) 
{ 
    int n = (int) (Math.Sqrt (m) + 1); 
  
    // Calculate a ^ n 
    int an = 1; 
    for (int i = 0; i < n; ++i) 
        an = (an * a) % m; 
  
    int[] value = new int[m]; 
  
    // Store all values of a^(n*i) of LHS 
    for (int i = 1, cur = an; i<= n; ++i) 
    { 
        if (value[ cur ] == 0) 
            value[ cur ] = i; 
        cur = (cur * an) % m; 
    } 
  
    for (int i = 0, cur = b; i<= n; ++i) 
    { 
        // Calculate (a ^ j) * b and check 
        // for collision 
        if (value[cur] > 0) 
        { 
            int ans = value[cur] * n - i; 
            if (ans < m) 
                return ans; 
        } 
        cur = (cur * a) % m; 
    } 
    return -1; 
} 
  
// Driver code 
static void Main() 
{ 
    int a = 2, b = 3, m = 5; 
    Console.WriteLine(discreteLogarithm(a, b, m)); 
  
    a = 3;
    b = 7;
    m = 11; 
    Console.WriteLine(discreteLogarithm(a, b, m)); 
} 
}
  
// This code is contributed by mits


PHP


输出:

3
-1

时间复杂度: O(sqrt(m)* log(b))
辅助空间: O(sqrt(m))

一种可能的改进是在算法的第二阶段中消除二进制乘幂或log(b)因子。这可以通过保持每次乘以“ a”的变量作为“ an”来完成。让我们看一下该程序以了解更多信息。

C++

// C++ program to calculate discrete logarithm
#include
using namespace std;
  
int discreteLogarithm(int a, int b, int m) 
{
    int n = (int) sqrt (m) + 1;
  
    // Calculate a ^ n 
    int an = 1;
    for (int i = 0; i value;
  
    // Store all values of a^(n*i) of LHS
    for (int i = 1, cur = an; i<= n; ++i)
    {
        if (! value[ cur ])
            value[ cur ] = i;
        cur = (cur * an) % m;
    }
  
    for (int i = 0, cur = b; i<= n; ++i)
    {
        // Calculate (a ^ j) * b and check
        // for collision
        if (value[cur])
        {
            int ans = value[cur] * n - i;
            if (ans < m)
                return ans;
        }
        cur = (cur * a) % m;
    }
    return -1;
}
  
// Driver code
int main()
{
    int a = 2, b = 3, m = 5;
    cout << discreteLogarithm(a, b, m) << endl;
  
    a = 3, b = 7, m = 11;
    cout << discreteLogarithm(a, b, m);
}

Java

// Java program to calculate discrete logarithm 
  
class GFG
{
  
    static int discreteLogarithm(int a, int b, int m) 
    { 
        int n = (int) (Math.sqrt (m) + 1); 
  
        // Calculate a ^ n 
        int an = 1; 
        for (int i = 0; i < n; ++i) 
            an = (an * a) % m; 
  
        int[] value=new int[m]; 
  
        // Store all values of a^(n*i) of LHS 
        for (int i = 1, cur = an; i <= n; ++i) 
        { 
            if (value[ cur ] == 0) 
                value[ cur ] = i; 
            cur = (cur * an) % m; 
        } 
  
        for (int i = 0, cur = b; i <= n; ++i) 
        { 
            // Calculate (a ^ j) * b and check 
            // for collision 
            if (value[cur] > 0) 
            { 
                int ans = value[cur] * n - i; 
                if (ans < m) 
                    return ans; 
            } 
            cur = (cur * a) % m; 
        } 
        return -1; 
    } 
  
    // Driver code 
    public static void main(String[] args) 
    { 
        int a = 2, b = 3, m = 5; 
        System.out.println(discreteLogarithm(a, b, m)); 
        a = 3;
        b = 7;
        m = 11; 
        System.out.println(discreteLogarithm(a, b, m)); 
    } 
}
  
// This code is contributed by mits

Python3

# Python3 program to calculate 
# discrete logarithm
import math;
  
def discreteLogarithm(a, b, m): 
  
    n = int(math.sqrt (m) + 1);
  
    # Calculate a ^ n 
    an = 1;
    for i in range(n):
        an = (an * a) % m;
  
    value = [0] * m;
  
    # Store all values of a^(n*i) of LHS
    cur = an;
    for i in range(1, n + 1):
        if (value[ cur ] == 0):
            value[ cur ] = i;
        cur = (cur * an) % m;
      
    cur = b;
    for i in range(n + 1):
          
        # Calculate (a ^ j) * b and check
        # for collision
        if (value[cur] > 0):
            ans = value[cur] * n - i;
            if (ans < m):
                return ans;
        cur = (cur * a) % m;
  
    return -1;
  
# Driver code
a = 2;
b = 3;
m = 5;
print(discreteLogarithm(a, b, m));
  
a = 3;
b = 7;
m = 11;
print(discreteLogarithm(a, b, m));
  
# This code is contributed by mits

C#

// C# program to calculate discrete logarithm 
using System;
  
class GFG 
{
      
static int discreteLogarithm(int a, int b, int m) 
{ 
    int n = (int) (Math.Sqrt (m) + 1); 
  
    // Calculate a ^ n 
    int an = 1; 
    for (int i = 0; i < n; ++i) 
        an = (an * a) % m; 
  
    int[] value = new int[m]; 
  
    // Store all values of a^(n*i) of LHS 
    for (int i = 1, cur = an; i<= n; ++i) 
    { 
        if (value[ cur ] == 0) 
            value[ cur ] = i; 
        cur = (cur * an) % m; 
    } 
  
    for (int i = 0, cur = b; i<= n; ++i) 
    { 
        // Calculate (a ^ j) * b and check 
        // for collision 
        if (value[cur] > 0) 
        { 
            int ans = value[cur] * n - i; 
            if (ans < m) 
                return ans; 
        } 
        cur = (cur * a) % m; 
    } 
    return -1; 
} 
  
// Driver code 
static void Main() 
{ 
    int a = 2, b = 3, m = 5; 
    Console.WriteLine(discreteLogarithm(a, b, m)); 
  
    a = 3;
    b = 7;
    m = 11; 
    Console.WriteLine(discreteLogarithm(a, b, m)); 
} 
}
  
// This code is contributed by mits

的PHP


输出:

3
-1

时间复杂度: O(sqrt(m))
辅助空间: O(sqrt(m))

参考:
http://e-maxx-eng.appspot.com/algebra/discrete-log.html
https://zh.wikipedia.org/wiki/Baby-step_giant-step