【问题标题】:Calculate discrete logarithm计算离散对数
【发布时间】:2009-12-02 12:27:57
【问题描述】:

给定正整数b, c, m 其中(b < m) is True 是要找到一个正整数e 使得

(b**e % m == c) is True

其中 ** 是取幂(例如,在 Ruby、Python 或某些其他语言中的 ^ 中),% 是模运算。解决这个问题的最有效算法(big-O 复杂度最低)是什么?

例子:

给定 b=5; c=8; m=13 这个算法必须找到 e=7 因为 5**7%13 = 8

【问题讨论】:

    标签: algorithm math


    【解决方案1】:

    通过 % 运算符,我假设您正在使用整数。

    您正在尝试解决the Discrete Logarithm 问题。一个合理的算法是Baby step, giant step,虽然还有很多其他的,都不是特别快。

    很难找到离散对数问题的快速解决方案是一些流行的密码算法的基本部分,因此如果您找到比维基百科上的任何解决方案更好的解决方案,请告诉我!

    【讨论】:

    • 见鬼,如果他找到了一个真正高效的算法,他很有可能获得菲尔兹奖
    【解决方案2】:

    这根本不是一个简单的问题。它被称为计算discrete logarithm,它是modular exponentation的逆运算。

    没有已知的有效算法。也就是说,如果 N 表示 m 中的位数,所有已知的算法都在 O(2^(N^C)) 中运行,其中 C>0。

    【讨论】:

    • 您声称对于某些 C > 1,所有已知算法都在 O(C^N) 时间内运行的说法是不正确的。没有在多项式时间内运行的已知算法,但仍有已知的次指数算法。
    【解决方案3】:

    Python 3 解决方案:

    谢天谢地,SymPyimplemented 这个给你!

    SymPy 是用于符号数学的 Python 库。它旨在成为一个功能齐全的计算机代数系统(CAS),同时保持代码尽可能简单,以便易于理解和易于扩展。 SymPy 完全用 Python 编写。

    这是documentation on the discrete_log 函数。使用它来导入它:

    from sympy.ntheory import discrete_log
    

    他们的例子计算\log_7(15) (mod 41):

    >>> discrete_log(41, 15, 7)
    3
    

    由于它采用(最先进的,请注意)算法来解决这个问题,所以在您尝试的大多数输入中,您都会得到O(\sqrt{n})。当您的素数模数具有p - 1 分解为许多素数的属性时,它会快得多。

    考虑大约 100 位的素数:(~ 2^{100})。对于 \sqrt{n} 复杂性,这仍然是 2^{50} 次迭代。话虽如此,不要重新发明轮子。这做得很好。我还可以补充一点,当我使用大型输入(44 MiB 与 173 MiB)运行时,它的内存效率几乎是 Mathematica 的 MultiplicativeOrder 函数的 4 倍。

    【讨论】:

      【解决方案4】:

      由于在 Python 标记下询问了此问题的重复项,因此这里是婴儿步、巨步的 Python 实现,正如@MarkBeyers 指出的那样,这是一种合理的方法(只要模数不太大):

      def baby_steps_giant_steps(a,b,p,N = None):
          if not N: N = 1 + int(math.sqrt(p))
      
          #initialize baby_steps table
          baby_steps = {}
          baby_step = 1
          for r in range(N+1):
              baby_steps[baby_step] = r
              baby_step = baby_step * a % p
      
          #now take the giant steps
          giant_stride = pow(a,(p-2)*N,p)
          giant_step = b
          for q in range(N+1):
              if giant_step in baby_steps:
                  return q*N + baby_steps[giant_step]
              else:
                  giant_step = giant_step * giant_stride % p
          return "No Match"
      

      在上述实现中,即使p 在密码学上很大,也可以将显式N 传递给小指数。只要指数小于N**2,它就会找到指数。当N 被省略时,指数总是会被找到,但如果p 太大,则不一定在你的生命周期或你的机器内存中找到。

      例如,如果

      p = 70606432933607
      a = 100001
      b = 54696545758787
      

      然后 'pow(a,b,p)' 计算结果为 67385023448517

      >>> baby_steps_giant_steps(a,67385023448517,p)
      54696545758787
      

      这在我的机器上花了大约 5 秒钟。对于这些大小的指数和模数,我估计(基于时间实验)蛮力需要几个月的时间。

      【讨论】:

        【解决方案5】:

        Discrete logarithm 是个难题

        计算离散对数被认为是困难的。不 计算离散对数的有效通用方法 传统计算机是众所周知的。

        我将在这里添加一个简单的蛮力算法,它会尝试从1m 的所有可能值,如果找到则输出解决方案。请注意,问题的解决方案可能不止一种,也可能根本没有解决方案。此算法将返回可能的最小值或-1(如果不存在)。

        def bruteLog(b, c, m):
            s = 1
            for i in xrange(m):
                s = (s * b) % m
                if s == c:
                    return i + 1
            return -1
        
        print bruteLog(5, 8, 13)
        

        在这里您可以看到3 实际上是解决方案:

        print 5**3 % 13
        

        有一个更好的算法,但是因为经常被要求在编程比赛中实现,所以我只是给你一个链接到explanation

        【讨论】:

          【解决方案6】:

          如前所述,一般问题很难。但是,当且仅当您知道 e 会很小(例如在您的示例中)时,找到 e 的实用方法就是尝试从 1 开始的每个 e。

          btw e==3 是您示例的第一个解决方案,您显然可以在 3 个步骤中发现,与解决非离散版本相比,并且天真地寻找整数解决方案,即

          e = log(c + n*m)/log(b) 其中 n 是一个非负整数

          在 9 步中找到 e==3

          【讨论】:

            猜你喜欢
            • 2023-03-31
            • 1970-01-01
            • 1970-01-01
            • 2012-04-30
            • 1970-01-01
            • 1970-01-01
            • 2023-03-12
            • 1970-01-01
            相关资源
            最近更新 更多