基于
Z
p
∗
Z^*_p
Zp∗的离散对数问题(DLP)
给定一个阶为
p
−
1
p-1
p−1 的有限循环群
Z
p
∗
Z^*_p
Zp∗,一个本原元
α
∈
Z
p
∗
α \in Z^*_p
α∈Zp∗和另一个元素
β
∈
Z
p
∗
{\beta} \in Z^*_p
β∈Zp∗。DLP是确定满足以下条件的整数
x
x
x(其中
1
≤
x
≤
p
−
1
1≤x≤p-1
1≤x≤p−1)的问题:
α
x
=
β
m
o
d
p
α^x ={\beta}mod p
αx=βmodp
有群
Z
p
∗
Z^*_p
Zp∗的性质可知这样的整数
x
x
x肯定存在,因为
α
α
α是一个本原元,而每个群元素可以表示为任何本原元的幂值。这个整数
x
x
x也称为以
α
α
α为基的
β
β
β的离散对数,可以正式地写作:
x
=
log
α
β
m
o
d
p
x = {\log}_{\alpha}{\beta} mod p
x=logαβmodp
如果参数足够大的话,计算离散对数模一个素数是一个非常难的问题。因为指数运算
α
x
=
β
m
o
d
p
α^x ={\beta}mod p
αx=βmodp计算起来非常简单,这也形成了一个单向函数。
示例1:考虑群 Z 47 ∗ Z^*_{47} Z47∗内的离散对数,其中本原元为 α = 5 α =5 α=5。对 β = 41 β=41 β=41的离散对数问题为:找到满足下面条件的正整数 x x x: 5 x = 41 m o d 47. 5^x = 41 mod 47. 5x=41mod47. 即使使用这么小的数字,确定 x x x也不是很容易。使用蛮力攻击,即系统地尝试所有可能的 x x x值,可得到解 x = 15 x= 15 x=15。

在实际中,为了防止 Pohlig-Hellman攻击,群内DLP的基数最好是素数。由于群 Z p ∗ Z^*_p Zp∗(p为素数)的基为 p − 1 p-1 p−1,而这个数显然不是素数,所以人们常会选择 Z p ∗ Z^*_p Zp∗子群中基为素数的子群内的 DLP,而非直接使用群 Z p ∗ Z^*_p Zp∗本身。下面将用示例2进行说明。
示例2:群 Z 47 ∗ Z^*_{47} Z47∗阶为46,因此, Z 47 ∗ Z^*_{47} Z47∗中的子群对应的基有23、2和1。 α = 2 α = 2 α=2是拥有23个元素的子群的一个元素,因为23是一个素数,而 α α α是子群内的本原元。 β = 36 β=36 β=36(也在子群中)对应的一个可能的离散对数问题为:找到一个正整数 x ( 1 ≤ x ≤ 23 ) x(1≤x≤23 ) x(1≤x≤23),使得 2 x = 36 m o d 47. 2^x = 36 mod 47. 2x=36mod47. 利用蛮力攻击可以找到解 x = 17 x= 17 x=17。

针对示例1、2中的暴力破解程序:
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* @Author Mr.Lu
* @Date 2022/7/27 19:22
* @ClassName DLPTest
* @Version 1.0
*/
public class DLPTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入群Z_n中的n: ");
int Z_n = sc.nextInt();
System.out.println("请输入群Z_n中的一个逆元(本原元): ");
int a = sc.nextInt();
System.out.println("请输入群Z_n中的一个元素: ");
int b = sc.nextInt();
int[] nums = findNums(Z_n);
int res = findX(nums, a, b, Z_n);
System.out.println("利用蛮力攻击找到的解为:" + res);
}
/**
* 针对离散对数问题进行暴力破解,查找符合条件的x
* @param nums
* @param a
* @param b
* @param Z
* @return
*/
private static int findX(int[] nums, int a, int b, int Z) {
for (int i = 0; i < nums.length; i++) {
if(((Math.pow(a, i) - b) % Z) == 0){
return i;
}
}
return -1; // 不存在,返回-1作为结束的标志
}
/**
* 求群Z内的元素
* @param Z
* @return
*/
private static int[] findNums(int Z) {
List<Integer> list = new ArrayList<>();
for(int i = 1; i < Z; i++){
if(gcd(i, Z) == 1){
list.add(i);
}
}
int[] nums = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
nums[i] = list.get(i);
}
return nums;
}
/**
* 求两个数的最大公约数
* @param num
* @param Z
* @return
*/
private static int gcd(int num, int Z) {
if(num == 1) return 1;
int temp = num;
num = Z % num;
Z = temp;
return gcd(num, Z);
}
}
推广的离散对数问题
DLP在密码学中有一个重要特征:它并没有限制在乘法群
Z
p
∗
Z^*_{p}
Zp∗(p是一个素数)内,而是可以定义在任何循环群中。这也称为推广的离散对数(GDLP)问题,可以描述为:
给定一个基为 n n n的有限循环群 G G G,群操作为 o o o。考虑一个本原元 α ∈ G \alpha \in G α∈G和另一个元素 β ∈ G \beta \in G β∈G,则离散对数问题为:找到在 1 ≤ x ≤ n 1≤ x ≤ n 1≤x≤n内的整数 x x x,满足: β = α o α o . . . o α ⏟ x 次 = α x \beta = \underbrace{{\alpha} o {\alpha} o ...o {\alpha}}_{x次} = {\alpha}^x β=x次 αoαo...oα=αx
与 Z p ∗ Z^*_{p} Zp∗内DLP的情况一样,这样的整数 x x x一定存在,因为 α α α是一个本原元,因此群 G G G内的每个元素都可以通过 α α α上重复使用群操作得到。
注意:有些循环群中的DLP并不是很困难的。这样的群就不能用于公钥密码体制,因为这样的群内的DLP并不是一个单向函数。例如下面的示例:
示例:将考虑整数模素数的加法群。例如,如果选择的素数为
p
=
11
,
G
=
(
Z
11
,
+
)
p = 11,G = (Z_{11}, +)
p=11,G=(Z11,+)是本原元为
α
=
2
α =2
α=2的一个有限循环群。
α
α
α生成该群的过程如下:
现在求解元素
β
=
3
β=3
β=3的 DLP,即必须计算整数
1
≤
x
≤
11
1 ≤ x ≤ 11
1≤x≤11中,满足以下条件的
x
x
x:
x
∗
2
=
2
+
2
+
.
.
.
+
2
⏟
x
次
≡
3
m
o
d
11
x*2 = \ \underbrace{2 + 2 + ... + 2}_{x次} \equiv 3 mod 11
x∗2= x次
2+2+...+2≡3mod11 针对此DLP 的攻击方式。尽管群操作为加法,但是
α
\alpha
α,
β
\beta
β以及离散对数
x
x
x之间的关系可以用乘法来表示:
x
∗
2
≡
3
m
o
d
11
x*2 \equiv 3 mod 11
x∗2≡3mod11 可以将本原元
α
=
2
α=2
α=2求逆来求解
x
x
x的值:
x
≡
2
−
1
∗
3
m
o
d
11
x \equiv 2^{-1}*3 mod 11
x≡2−1∗3mod11 根据根据扩展的欧几里得算法可知
2
−
1
≡
6
m
o
d
11
2^{-1}\equiv 6 mod 11
2−1≡6mod11, 那么离散对数为:
x
≡
2
−
1
∗
3
≡
7
m
o
d
11
x \equiv 2^{-1}*3 \equiv 7mod 11
x≡2−1∗3≡7mod11
这个离散对数可以从上面给出的小表中验证。
上面的技巧可以推广到
n
n
n为任意值,且元素
α
,
β
∈
Z
n
\alpha, \beta \in Z_n
α,β∈Zn的任何群
(
Z
n
,
+
)
(Z_n,+)
(Zn,+)中。可以得到这样一个结论: 在
Z
n
Z_n
Zn上计算推广的DLP会非常简单。这里能非常容易求解 DLP的原因在于,其中有些数学操作都不在加法群里,即乘法和逆元。
我们可以注意到使用基本 DHKE 的协议在主动攻击(攻击者可以修改消息或者生成消息)面前并不是安全的。这意味着如果攻击者Oscar可以修改消息或生成假消息,则Oscar就可以破解这个协议。这称为中间人攻击。
目前我们只考虑消极攻击者的可能性**,即 Oscar只能监听消息但不能篡改消息**。Oscar的目的就是计算Alice与Bob之间共享的会话密钥
k
A
B
k_{AB}
kAB。通过观察协议Oscar可以获得什么信息?下面分析一下:
问题提出:Oscar能否从 α , p , A ≡ α a m o d p α, p ,A \equiv {\alpha}^a mod p α,p,A≡αamodp 和 B ≡ α b m o d p B \equiv {\alpha}^b mod p B≡αbmodp中计算出 k = α k= α k=α。这个问题也称为Diffie-Hellman问题(DHP)。与离散对数问题一样,Diffie-Hellman问题也可推广到任意的有限循环群。
下面是DHP的正式描述:
给定一个阶为
n
n
n的有限循环群
G
G
G,一个本原元
α
∈
G
α \in G
α∈G及两个 G 内的元素
A
=
α
a
A = {\alpha}^a
A=αa 与
B
=
α
b
B = {\alpha}^b
B=αb。Diffie-Hellman问题就是找到群元素
α
a
b
{\alpha}^{ab}
αab。
求解 Diffie-Hellman 问题的一个通用方法如下。为了便于理解我们以乘法群 Z p ∗ Z^*_p Zp∗ 内的 DHP 作为例子。假设 Oscar 知道计算 Z p ∗ Z^*_p Zp∗ 内离散对数的有效方法——当然,这是一个“很大”的假设。然后,Oscar就可以通过以下两步求解出 Diffie-Hellman问题,并得到密钥 k A B k_{AB} kAB:
尽管这些步骤看上去很简单,但如果p足够大,则计算离散对数问题仍然是不可行的, 即这个假设是以解决离散对数问题为前提的。
注意:我们并不知道求解DLP是否是求解DHP的唯一方法。理论上,不用计算离散对数就能求解DHP的方法也是可能的。这个情况与RSA类似———在RSA中,因式分解是否真的是破解RSA最好的方法是未知的。然而,尽管这个结论在数学书是不可证明的,但人们通常假设有效求解DLP是有效求解DHP的唯一方法(即解决DLP是解决DHP的前提)。因此,为了保证实际中DHKE的安全性,我们必须确保对应的 DLP不能被求解。而这一点是通过选择足够大的
p
p
p,使得 index-calculus方法不能计算 DLP而实现的。
一些代数知识(群、循环群和子群):
https://blog.csdn.net/qq_43751200/article/details/125978990
公钥算法的基本数论知识(欧几里得算法、扩展欧几里得算法、欧拉函数、费马小定理与欧拉定理):
https://blog.csdn.net/qq_43751200/article/details/125460326
《深入浅出密码学》–Christof Paar,Jan Pelzl著