基于离散对数问题的公钥密码体制(二):离散对数问题

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

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

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

给定一个阶为 n n n的群 G G G,群操作为 ∘ \circ ,有一生成元 α ∈ G \alpha \in G αG以及一元素 β ∈ G \beta \in G βG,找到一个满足 1 ≤ x ≤ n 1 \le x \le n 1xn的整数 x x x,满足:
β = α ∘ α ∘ ⋯ ∘ α ⏟ x 次 = α x , \beta = \underbrace{\alpha \circ \alpha \circ \dots \circ \alpha}_{x次} = \alpha^{x}, β=x ααα=αx
也可表示为:
x = log ⁡ α β . x = \rm{\log}_{\alpha}{\beta}. x=logαβ.

DLP可被用来构造单向函数,单向函数指的是假设有一个函数 F F F,已知输入 x x x计算 y = F ( x ) y=F(x) y=F(x)是计算简单的,而已知输出 y y y计算 x = F − 1 ( y ) x=F^{-1}(y) x=F1(y)在计算上是困难的。带入到DLP中,我们可以得到正向问题为: β = F ( x ) = α x \beta = F(x)=\alpha^x β=F(x)=αx;而逆向问题为: x = F − 1 ( β ) = log ⁡ α β x = F^{-1}(\beta) = \rm{\log}_{\alpha}{\beta} x=F1(β)=logαβ​。如果选择了合适的群,那么正向计算出 β \beta β很容易,而逆向计算出 α \alpha α是个很困难的问题。

为了方便大家对DLP的理解,这里先介绍基于群 Z p ∗ \mathbb{Z}_p^* Zp​的DLP,其中 p p p​是一个素数。在上一篇文章中介绍过, Z p ∗ \mathbb{Z}_p^* Zp​是由小于 n n n​且与 n n n​互素的正整数所构成的集合, Z p ∗ \mathbb{Z}_p^* Zp​对于模 q q q​的乘法构成一个阿贝尔有限循环群。如果参数足够大的话,在群 ( Z p ∗ , ⋅ ) (\mathbb{Z}_p^{*},\cdot) (Zp,)中计算离散对数是个非常困难的问题。

示例1

考虑群 Z 47 ∗ \mathbb{Z}_{47}^* Z47内的DLP,其中该群生成元为 α = 5 \alpha = 5 α=5,对于 β = 41 \beta = 41 β=41的DLP可以被表示为:
x ≡ log ⁡ 5 41   m o d   47. x \equiv \log_5{41}~\rm{mod}~47. xlog541 mod 47.
找到 x x x的唯一办法就是暴力搜索,即尝试所有可能的 x x x值,最终得到 x = 15 x=15 x=15。但即使是用这么小的数字,找到 x x x​也不是一件容易事。

在实际中,为了安全性(主要为了防止Pohlig-Hellman攻击),群的阶数最好是素数,对于上面提到的 Z p ∗ \mathbb{Z}_p^* Zp,其阶为 p − 1 p-1 p1,显然不是素数,所以人们常会选择 Z p ∗ \mathbb{Z}_p^* Zp的子群中阶为素数的子群来建立DLP,而不是 Z p ∗ \mathbb{Z}_p^* Zp本身。

示例2

Z 47 ∗ \mathbb{Z}_{47}^* Z47的阶为46,根据前一篇文章中的子群性质,可知 Z 47 ∗ \mathbb{Z}_{47}^* Z47的子群的阶只能为1、2、23,由于 o r d ( 2 ) = 23 ord(2)=23 ord(2)=23,所以 α = 2 \alpha = 2 α=2 Z 47 ∗ \mathbb{Z}_{47}^* Z47的有23个元素的子群 H H H的生成元。我们找到一个元素 β ∈ H \beta \in H βH,其中 β = 36 \beta = 36 β=36,建立DLP:找到一个正整数 x x x 1 ≤ x ≤ 23 1 \le x \le 23 1x23)使得
36 ≡ 2 x   m o d   47. 36 \equiv 2^{x}~\rm{mod}~47. 362x mod 47.
利用暴力搜索可以得到x=17。

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

示例3

考虑整数模素数加法群,例如 ( Z 11 , + ) (\mathbb{Z}_{11}, +) (Z11,+)是一个生成元为 α = 2 \alpha = 2 α=2的有限循环群,下表能够展示出 α \alpha α生成整个群的过程:

i1234567891011
α i \alpha^i αi246810135790

现在我们设 β = 3 \beta = 3 β=3,建立DLP:找到一个整数 x x x 1 ≤ x ≤ 11 1 \le x \le 11 1x11)使得
2 + 2 + ⋯ + 2 ⏟ x 次 ≡ 3   m o d   11 \underbrace{2+2+\dots+2}_{x次} \equiv 3~\rm{mod}~11 x 2+2++23 mod 11

x ⋅ 2 ≡ 3   m o d   11. x\cdot2 \equiv 3~\rm{mod}~11. x23 mod 11.
虽然该群中的运算是模11加法,但是 α \alpha α β \beta β x x x​之间的关系却可以被模11乘法表示,那么为了求解 x x x,可以简单地对 α \alpha α求逆元:
x ≡ 2 − 1 ⋅ 3   m o d   11 x \equiv 2^{-1}\cdot3 ~\rm{mod}~11 x213 mod 11
求逆元的算法并不复杂,可以根据扩展欧几里得算法(后续文章会提到)计算出 2 − 1 ≡ 6   m o d   11 2^{-1}\equiv 6 ~\rm{mod}~11 216 mod 11​,然后就能得到:
x ≡ 7   m o d   11. x\equiv 7~\rm{mod}~11. x7 mod 11.
从上面的表格就能验证出这个结果是正确的。

上面示例3的结果可以被推广到 n n n为任意值且元素 α \alpha α β ∈ Z n \beta \in \mathbb{Z}_n βZn的任何群 ( Z n , + ) (\mathbb{Z}_{n}, +) (Zn,+)中,因此可以得到结论在 Z n \mathbb{Z}_n Zn中计算推广的DLP会非常简单。

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

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

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

BSGS算法的思想是将群 G G G中离散对数 x = log ⁡ α β x=\log_{\alpha}{\beta} x=logαβ​重写为
x = x g m + x b ,   0 ≤ x g , x b < m . x = x_gm+x_b,~0 \le x_g, x_b < m. x=xgm+xb, 0xg,xb<m.
通常情况下 m m m的大小选择为群的阶的平方根,即 m = ⌈ ∣ G ∣ ⌉ m=\lceil \sqrt{|G|} \rceil m=G 。下面可以将离散对数进行变形:
β = α x g m + x b β ( α − m ) x g = α x b \begin{aligned} \beta &= \alpha^{x_gm+x_b} \\ \beta (\alpha^{-m})^{x_g} &= \alpha^{x_b} \end{aligned} ββ(αm)xg=αxgm+xb=αxb
算法的核心思想就是找到上面方程的解 ( x g , x b ) (x_g, x_b) (xg,xb),进而就能得到离散对数问题的解 x x x。该算法分为两阶段,即baby-step和giant-step。

Baby-Step

在此阶段,要计算并存储所有 α x b \alpha ^ {x_b} αxb​的值,其中 0 ≤ x b < m 0 \le x_b < m 0xb<m​。这一步需要 m m m个群操作,并需要存储 m m m个群元素。

Giant-Step

在此阶段,算法检查 0 ≤ x g < m 0 \le x_g < m 0xg<m​范围内所有的 x g x_g xg,并判断baby-step阶段计算的一些易存储的项 α x b \alpha ^ {x_b} αxb是否满足以下条件:
β ( α − m ) x g = ? α x b \beta (\alpha^{-m})^{x_g} \overset{?}{=} \alpha^{x_b} β(αm)xg=?αxb
如果上面等式成立,那么就意味着找到了一个解 ( x g 0 , x b 0 ) (x_{g0}, x_{b0}) (xg0,xb0)​​​​​满足上面的等式,这样离散对数问题的解 x x x就可以表示为
x = x g 0 m + x b 0 . x =x_{g0}m + x_{b0}. x=xg0m+xb0.
BSGS算法需要 O ( ∣ G ∣ ) \mathcal{O}(\sqrt{|G|}) O(G )计算复杂度和相同大小的存储复杂度,因此一般为了追求 2 80 2^{80} 280的攻击复杂度,群的阶至少为 ∣ G ∣ ≥ 2 160 |G|\ge2^{160} G2160,因此在 G = Z p ∗ G=\mathbb{Z}_p^* G=Zp中,素数 p p p的长度应该有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

写在最后

欢迎大家关注我的微信公众号,本人会不定期发一些有关密码学、区块链技术、编程等相关文章,欢迎志同道合的朋友来一起交流呀!
在这里插入图片描述

  • 26
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值