在上一篇文章当中花了较大篇幅对进行了介绍,通过循环群就可以对本文所提到的离散对数问题(DLP) 进行解释。

首先来看离散对数问题的一般定义:

定义1. 离散对数问题(DLP)

给定一个阶为DLP和NLP dlp和nlp大于9_单向函数的群DLP和NLP dlp和nlp大于9_单向函数_02,群操作为DLP和NLP dlp和nlp大于9_单向函数_03,有一生成元DLP和NLP dlp和nlp大于9_DLP和NLP_04以及一元素DLP和NLP dlp和nlp大于9_ci_05,找到一个满足DLP和NLP dlp和nlp大于9_DLP和NLP_06的整数DLP和NLP dlp和nlp大于9_密码学_07,满足:
DLP和NLP dlp和nlp大于9_密码学_08
也可表示为:
DLP和NLP dlp和nlp大于9_单向函数_09

DLP可被用来构造单向函数,单向函数指的是假设有一个函数DLP和NLP dlp和nlp大于9_DLP和NLP_10,已知输入DLP和NLP dlp和nlp大于9_密码学_11计算DLP和NLP dlp和nlp大于9_离散对数问题_12是计算简单的,而已知输出DLP和NLP dlp和nlp大于9_单向函数_13计算DLP和NLP dlp和nlp大于9_ci_14在计算上是困难的。带入到DLP中,我们可以得到正向问题为:DLP和NLP dlp和nlp大于9_DLP和NLP_15;而逆向问题为:DLP和NLP dlp和nlp大于9_离散对数问题_16。如果选择了合适的群,那么正向计算出DLP和NLP dlp和nlp大于9_密码学_17很容易,而逆向计算出DLP和NLP dlp和nlp大于9_单向函数_18是个很困难的问题。

为了方便大家对DLP的理解,这里先介绍基于群DLP和NLP dlp和nlp大于9_ci_19的DLP,其中DLP和NLP dlp和nlp大于9_单向函数_20是一个素数。在上一篇文章中介绍过,DLP和NLP dlp和nlp大于9_ci_19是由小于DLP和NLP dlp和nlp大于9_密码学_22且与DLP和NLP dlp和nlp大于9_密码学_22互素的正整数所构成的集合,DLP和NLP dlp和nlp大于9_ci_19对于模DLP和NLP dlp和nlp大于9_单向函数_25的乘法构成一个阿贝尔有限循环群。如果参数足够大的话,在群DLP和NLP dlp和nlp大于9_密码学_26中计算离散对数是个非常困难的问题。

示例1

考虑群DLP和NLP dlp和nlp大于9_DLP和NLP_27内的DLP,其中该群生成元为DLP和NLP dlp和nlp大于9_DLP和NLP_28,对于DLP和NLP dlp和nlp大于9_DLP和NLP_29的DLP可以被表示为:
DLP和NLP dlp和nlp大于9_ci_30
找到DLP和NLP dlp和nlp大于9_密码学_11的唯一办法就是暴力搜索,即尝试所有可能的DLP和NLP dlp和nlp大于9_密码学_11值,最终得到DLP和NLP dlp和nlp大于9_单向函数_33。但即使是用这么小的数字,找到DLP和NLP dlp和nlp大于9_密码学_11也不是一件容易事。

在实际中,为了安全性(主要为了防止Pohlig-Hellman攻击),群的阶数最好是素数,对于上面提到的DLP和NLP dlp和nlp大于9_ci_19,其阶为DLP和NLP dlp和nlp大于9_单向函数_36,显然不是素数,所以人们常会选择DLP和NLP dlp和nlp大于9_ci_19的子群中阶为素数的子群来建立DLP,而不是DLP和NLP dlp和nlp大于9_ci_19本身。

示例2

DLP和NLP dlp和nlp大于9_DLP和NLP_27的阶为46,根据前一篇文章中的子群性质,可知DLP和NLP dlp和nlp大于9_DLP和NLP_27的子群的阶只能为1、2、23,由于DLP和NLP dlp和nlp大于9_DLP和NLP_41,所以DLP和NLP dlp和nlp大于9_ci_42DLP和NLP dlp和nlp大于9_DLP和NLP_27的有23个元素的子群DLP和NLP dlp和nlp大于9_DLP和NLP_44的生成元。我们找到一个元素DLP和NLP dlp和nlp大于9_密码学_45,其中DLP和NLP dlp和nlp大于9_密码学_46,建立DLP:找到一个正整数DLP和NLP dlp和nlp大于9_密码学_11DLP和NLP dlp和nlp大于9_ci_48)使得
DLP和NLP dlp和nlp大于9_DLP和NLP_49
利用暴力搜索可以得到x=17。

需要注意的一点是,并不是在所有循环群中的DLP都是困难的,这样的循环群就不能被用于构造DLP难题,DLP也不会是一个单向函数。

示例3

考虑整数模素数加法群,例如DLP和NLP dlp和nlp大于9_单向函数_50是一个生成元为DLP和NLP dlp和nlp大于9_ci_42的有限循环群,下表能够展示出DLP和NLP dlp和nlp大于9_单向函数_18生成整个群的过程:

i

1

2

3

4

5

6

7

8

9

10

11

DLP和NLP dlp和nlp大于9_单向函数_53

2

4

6

8

10

1

3

5

7

9

0

现在我们设DLP和NLP dlp和nlp大于9_ci_54,建立DLP:找到一个整数DLP和NLP dlp和nlp大于9_密码学_11DLP和NLP dlp和nlp大于9_单向函数_56)使得
DLP和NLP dlp和nlp大于9_ci_57

DLP和NLP dlp和nlp大于9_单向函数_58
虽然该群中的运算是模11加法,但是DLP和NLP dlp和nlp大于9_单向函数_18DLP和NLP dlp和nlp大于9_密码学_17DLP和NLP dlp和nlp大于9_密码学_11之间的关系却可以被模11乘法表示,那么为了求解DLP和NLP dlp和nlp大于9_密码学_11,可以简单地对DLP和NLP dlp和nlp大于9_单向函数_18求逆元:
DLP和NLP dlp和nlp大于9_DLP和NLP_64
求逆元的算法并不复杂,可以根据扩展欧几里得算法(后续文章会提到)计算出DLP和NLP dlp和nlp大于9_密码学_65,然后就能得到:
DLP和NLP dlp和nlp大于9_ci_66
从上面的表格就能验证出这个结果是正确的。

上面示例3的结果可以被推广到DLP和NLP dlp和nlp大于9_密码学_22为任意值且元素DLP和NLP dlp和nlp大于9_单向函数_18DLP和NLP dlp和nlp大于9_单向函数_69的任何群DLP和NLP dlp和nlp大于9_单向函数_70中,因此可以得到结论在DLP和NLP dlp和nlp大于9_离散对数问题_71中计算推广的DLP会非常简单。

介绍完反例以后,下面列举一些密码学中推荐使用的一些离散对数问题:

  1. 素数域DLP和NLP dlp和nlp大于9_ci_72的乘法群或其子群,例如古典Diffie-Hellman密钥交换、ElGamal或数字签名算法(DSA)都用到了这个群;
  2. 椭圆曲线构成的循环群,后续文章会介绍到,它们如今逐渐占据了密码学主流位置;
  3. 伽罗瓦域DLP和NLP dlp和nlp大于9_DLP和NLP_73上的乘法群或其子群,和1的使用完全一致,但并不常用,因为针对其的攻击要比针对1的攻击更加强大,因此在提供相同安全等级的情况下基于DLP和NLP dlp和nlp大于9_DLP和NLP_73的DLP要求参数长度比1更长。

下面介绍一种非暴力搜索的解决离散对数问题的算法,名为Shanks’ Baby-Step Giant-Step方法,或简称为BSGS。BSGS是一个时间与内存平衡的方法,它通过额外的存储来减少蛮力搜索的时间。

BSGS算法的思想是将群DLP和NLP dlp和nlp大于9_单向函数_75中离散对数DLP和NLP dlp和nlp大于9_ci_76重写为
DLP和NLP dlp和nlp大于9_离散对数问题_77
通常情况下DLP和NLP dlp和nlp大于9_单向函数_78的大小选择为群的阶的平方根,即DLP和NLP dlp和nlp大于9_ci_79。下面可以将离散对数进行变形:
DLP和NLP dlp和nlp大于9_ci_80
算法的核心思想就是找到上面方程的解DLP和NLP dlp和nlp大于9_密码学_81,进而就能得到离散对数问题的解DLP和NLP dlp和nlp大于9_密码学_11。该算法分为两阶段,即baby-step和giant-step。

Baby-Step

在此阶段,要计算并存储所有DLP和NLP dlp和nlp大于9_DLP和NLP_83的值,其中DLP和NLP dlp和nlp大于9_DLP和NLP_84。这一步需要DLP和NLP dlp和nlp大于9_单向函数_78个群操作,并需要存储DLP和NLP dlp和nlp大于9_单向函数_78个群元素。

Giant-Step

在此阶段,算法检查DLP和NLP dlp和nlp大于9_DLP和NLP_87范围内所有的DLP和NLP dlp和nlp大于9_离散对数问题_88,并判断baby-step阶段计算的一些易存储的项DLP和NLP dlp和nlp大于9_DLP和NLP_83是否满足以下条件:
DLP和NLP dlp和nlp大于9_密码学_90
如果上面等式成立,那么就意味着找到了一个解DLP和NLP dlp和nlp大于9_离散对数问题_91满足上面的等式,这样离散对数问题的解DLP和NLP dlp和nlp大于9_密码学_11就可以表示为
DLP和NLP dlp和nlp大于9_DLP和NLP_93
BSGS算法需要DLP和NLP dlp和nlp大于9_ci_94计算复杂度和相同大小的存储复杂度,因此一般为了追求DLP和NLP dlp和nlp大于9_离散对数问题_95的攻击复杂度,群的阶至少为DLP和NLP dlp和nlp大于9_DLP和NLP_96,因此在DLP和NLP dlp和nlp大于9_DLP和NLP_97中,素数DLP和NLP dlp和nlp大于9_单向函数_20的长度应该有160bit。

下面是用Python3对BSGS算法的代码实现,关键步骤在代码中都有注释:

from math import sqrt, ceil


def bsgs_alg(alpha: int, beta: int, p: int) -> int:
    # 求出m
    m = ceil(sqrt(p - 1))

    # 初始化一个baby数组,存放baby-step结果
    baby = []

    x_g, x_b = -1, -1

    # baby-step
    baby.append(1)
    for i in range(1, m):
        baby.append((baby[i - 1] * alpha) % p)

    # 对生成元求逆
    alpha_inv = (alpha ** (p - 2)) % p
    # 求alpha逆元的m次幂
    alpha_pow = (alpha_inv ** m) % p

    # giant-step
    product = beta % p
    for j in range(m):
        try:
            # 查询baby表中是否有匹配的
            x_b = baby.index(product)
            x_g = j
            break
        except ValueError:
            product *= alpha_pow
            product %= p

    if x_b == -1:
        return x_b
    else:
        return x_g * m + x_b