Pohlig-Hellman算法求Elgamal算法私钥+大步小步法解决DLP(离散对数问题)

问题描述:在利用Elgamal算法公钥中,已知参数(本题中数字均为十进制整数)

p=26622572818608571599593915643850055101138771
g=65539,
小明的公钥为:
14632691854639937953996750549254161821338360
如果你知道模数p-1可以分解为
{{2, 1}, {3, 1}, {5, 1}, {7, 1}, {11, 1}, {13, 1}, {17, 1}, {19, 1}, {29, 1}, {31, 1}, {37, 1}, {41, 1}, {47, 1}, {53, 1}, {61, 1}, {73, 1}, {97, 1}, {101, 1}, {103, 1}, {107, 1}, {113, 1}, {137, 1}, {139, 1}, {151, 1}, {167, 1}, {173, 1}, {179, 1}}
请利用Pohlig–Hellman算法求私钥x;

一、大步小步法

(一)、原理:

g为p的原根,p-1是g的阶,求解问题为 x = l o g g β 。 x = {log}_g{\beta}。 x=loggβ

若使用穷举方法对x尝试0到p-1之间的数,验证 β = g x \beta=g^x β=gx,则算法复杂度为O(p-1)

小步大步法基于以下事实:

β = g x \beta = g^x β=gx,设 x = i ⋅ m + j x = i ·m+j x=im+j,其中 0 ≤ i , j < m 0\leq i,j < m 0i,j<m,如果令 m = p − 1 m=\sqrt{p-1} m=p1 ,此时建立一个条目为 ( j , g j ) (j,g^j) j,gj的表(j表的长度为 m ) \sqrt{m}) m ),则 i ⋅ m + j i ·m+j im+j可以遍历1到p-1的全部内容,并且遍历的复杂度取决于i,为 O ( p − 1 ) O(\sqrt{p-1}) O(p1 ),(m为定值,j已经存放在表中,建立j表的复杂度为 O ( p − 1 ) O(\sqrt{p-1}) O(p1 ,j表排序的复杂度为 O ( p − 1 ⋅ l o g p − 1 ) O(\sqrt{p-1}·{log}\sqrt{p-1}) O(p1 logp1 ),所以总复杂度为 O ( p − 1 ) O(\sqrt{p-1}) O(p1 )
p s : 在 x = i ⋅ m + j 中 ps:在x = i ·m+j中 ps:x=im+j,对于每个i,j,其变化较小每次加1,这是小步,而导致x每次变化的间隔较大为m(因为i·m),这是大步,即为小步大步法命名

大步小步法分析参考文章:https://blog.csdn.net/m0_66201040/article/details/124453140
复杂度分析:
在这里插入图片描述

(二)、实现思路

输入:生成元g的阶p-1和元 β \beta β
输出:离散对数 x = l o g g β x = {log}_g{\beta} x=loggβ
– 设置 m = ⌈ p − 1 ⌉ m =\lceil\sqrt{p-1}\rceil m=p1
– 建立一个条目为 的表(j, g j ( m o d p ) g^j(mod p) gj(modp)),其中 。以条目中的第二项对表排序
– 计算 和设置g^m
– 从0到m-1进行如下循环
• 检查 γ \gamma γ是否为表中某个第2项。
• 如果 γ ≡ g i ( m o d p ) \gamma \equiv g^i(mod p) γgi(modp),则返回(x=i·m+j)
• 设置 γ = γ ⋅ g − m \gamma = \gamma ·{g^{-m}} γ=γgm (其中 g − m 为 g m g^{-m}为g^m gmgm的模逆元)

(三)、代码实现

## n为g的阶
import gmpy2
def little_big_step_method(g,beta,N,p):# 求解x = (log_g)beta
    m = int(math.sqrt(N))+1
    gj_j_dict= {}
	# 建立(g^j,j)表,与上述原理(j,g^j表内容相反)
    for j in range(0,m):
        gj_j_dict[pow(g,j,p)] = j 
    gj_sorted_list = sorted(gj_j_dict)
    gamma = beta
    for i in range(0,m):
        if gamma in gj_sorted_list:
            return i*m + gj_j_dict[gamma]
        gamma = (gamma * gmpy2.invert(pow(g,m,p),p) )%p

二、Pohlig-Hellman

(一)、 原理

如果要求解x使得 β = g x m o d p \beta = g^x mod p β=gxmodp,g为素数p的原根,阶为p-1 ,如果 p − 1 = Π i = 1 t q i e i p-1= \Pi_{i=1}^{t}q_i^{e^i} p1=Πi=1tqiei,且 q i q^{i} qi互素,那么若能高效求出 x    m o d    q 1 e 1 , x    m o d    q 2 e 2 , . . . , x    m o d    q i e i x\;mod\;q_1^{e_1},x\;mod\;q_2^{e_2} ,...,x\;mod\;q_i^{e_i} xmodq1e1,xmodq2e2...xmodqiei,就可以使用中国剩余定理快速求出 x    m o d    ( p − 1 ) x\;mod\;(p-1) xmod(p1)

x i = x    m o d    q i e i x_i = x\;mod\;q_i^{e_i} xi=xmodqiei,则会有 x = k i ⋅ q i e i + r i , β = g x    m o d    x=k_i·q_i^{e_i}+r_i,\beta = g^x\;mod\; x=kiqiei+riβ=gxmod,p记g的阶为N=p-1则有:
β N q i e i m o d    p = ( g x ) N q i e i = g k i ⋅ N ⋅ g x i ⋅ N q i e i \beta^{\cfrac{N}{q_i^{e_i}}} mod\;p = (g^x)^{\cfrac{N}{q_i^{e_i}}} = g^{ki·N}·g^{x_i · {\cfrac{N}{q_i^{e_i}}}} βqieiNmodp=(gx)qieiN=gkiNgxiqieiN
由于 g k i ⋅ N    m o d    p = g k i ⋅ ( p − 1 )    m o d    p = 1    m o d    p g^{ki·N}\;mod\; p = g^{ki·(p-1)}\;mod\; p = 1\;mod\;p gkiNmodp=gki(p1)modp=1modp,所以:
β N q i e i m o d    p = g x i ⋅ N q i β e i = ( g N q i e i )    x i    m o d    p \beta^{\cfrac{N}{q_i^{e_i}}} mod\;p = g^{x_i · {\cfrac{N}{q_i^\beta{e_i}}}} = {(g^{{\cfrac{N}{q_i^{e_i}}}})}^{\;x_i}\;mod \;p βqieiNmodp=gxiqiβeiN=(gqieiN)ximodp
β ′ = β N q i e i , g ′ = g N q i e i \beta' =\beta^{\cfrac{N}{q_i^{e_i}}},g' = g^{{\cfrac{N}{q_i^{e_i}}}} β=βqieiNg=gqieiN,所以到这步,就需求解问题 β ′ = ( g ′ ) x i    m o d    p \beta' = (g')^{x_i}\;mod\;p β=(g)ximodp,即: x i = l o g g ′ β ′ x_i = {log}_{g'}^{\beta'} xi=loggβ,就用小步大步法或是穷举法求出

(二)、实现思路

输入:已知大素数P的元根为g , β \beta β 是一个小于P的数,g模P的阶是N=p-1, 以及N的素数分解 N = Π i = 1 t q i e i N = \Pi_{i=1}^tq_i^{e_i} N=Πi=1tqiei(t为N分解得到的素数的个数,相同的素数只记为一个)
输出:整数 x ∈ Z N x\in Z_N xZN ,且 g x = β    m o d    P g^x= \beta \;mod\;P gx=βmodP
1、对于每一个 i ∈ 1 , . . . , t i \in {1,...,t} i1,...,t
(1)计算 g i = g N q i e i g_i = g^{\cfrac{N}{q_i^{e_i}}} gi=gqieiN,易知g_i的阶是 q i e i q_i^{e_i} qiei(详见下图定理10.5)
(2)计算 h i = β N q i e i h_i = \beta^{\cfrac{N}{q_i^{e_i}}} hi=βqieiN h i ∈ < g i > h_i\in<g_i> hi∈<gi>
(3)使用穷举法或者大步小步法得到 x i x_i xi,使得 g i x i = h i {g_i}^{x_i}= h_i gixi=hi
2.利用中国剩余定理求解x,其中 x = x i    m o d    q i e i x=x_i \;mod\;q_i^{e_i} x=ximodqiei
在这里插入图片描述

(三)、代码实现

from hashlib import new
import math
import gmpy2


def little_big_step_method(g,beta,N,p):# 求解x = (log_g)beta
    m = int(math.sqrt(N))+1
    gj_j_dict= {}
	# 建立(g^j,j)表,与上述原理(j,g^j表内容相反)
    for j in range(0,m):
        gj_j_dict[pow(g,j,p)] = j 
    gj_sorted_list = sorted(gj_j_dict)
    gamma = beta
    for i in range(0,m):
        if gamma in gj_sorted_list:
            return i*m + gj_j_dict[gamma]
        gamma = (gamma * gmpy2.invert(pow(g,m,p),p) )%p
def solve_g_i(g,q_i,N):
    g_i = []
    for q in q_i:
        g_i.append(pow(g,(N//q),N+1))
    return g_i
def solve_h_i(beta,q_i,N):
    h_i = []
    for q in q_i:
        h_i.append(pow(beta,(N//q),N+1))
    return h_i
if __name__ == '__main__':
    beta = 14632691854639937953996750549254161821338360
    p=26622572818608571599593915643850055101138771
    g=65539
    N = p-1
    L = [[2, 1], [3, 1], [5, 1], [7, 1], [11, 1], [13, 1], [17, 1], [19, 1], [29, 1], [31, 1], [37, 1], [41, 1], [47, 1], [53, 1], [61, 1], [73, 1], [97, 1], [101, 1], [103, 1], [107, 1], [113, 1], [137, 1], [139, 1], [151, 1], [167, 1], [173, 1], [179, 1]]
    q_i = []

    for i in range(len(L)):
        q_i.append(L[i][0])
    g_i = [pow(g,N//q_i[i],p) for i in range(len(q_i))]
    h_i = [pow(beta,N//q_i[i],p) for i in range(len(q_i))]
    x_i = []
    # searchAll method
    # for i in range(len(q_i)):
    #     for j in range(q_i[i]):
    #         if pow(g_i[i],j,p) == h_i[i]:
    #             x_i.append(j)
    #             break
    for i in range(len(q_i)):
        x_i.append(little_big_step_method(g_i[i],h_i[i],q_i[i],p))
x = 0
for i in range(len(x_i)):
    Mi = N // q_i[i]
    Mii = gmpy2.invert(Mi, q_i[i])
    x = (x + x_i[i] * Mi * Mii) % N
    
print("私钥x为:%d"%pow(g,x,p))

在这里插入图片描述

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
离散对数问题是计算一个数a模p的离散对数x,即满足a^x≡b(mod p)的最小非负整数x。Pohlig-Hellman算法是一种解离散对数问题算法,具体实现如下: ``` #include<stdio.h> #include<math.h> int prime[100000]; int isprime[100001]; void get_prime(int n) { int cnt = 0; for(int i = 2;i <= n;i++) { if(isprime[i] == 0) { prime[++cnt] = i; } for(int j = 1;j <= cnt;j++) { if(prime[j] * i > n) { break; } isprime[prime[j] * i] = 1; if(i % prime[j] == 0) { break; } } } } long long pow_mod(long long a, long long b, long long p) { long long ans = 1; a %= p; while(b) { if(b & 1) { ans = ans * a % p; } b >>= 1; a = a * a % p; } return ans; } long long inv(long long a, long long p) { return pow_mod(a, p - 2, p); } long long exgcd(long long a, long long b, long long &x, long long &y) { if(b == 0) { x = 1; y = 0; return a; } long long d = exgcd(b, a % b, y, x); y -= (a / b) * x; return d; } long long bsgs(long long a, long long b, long long p) { long long m = ceil(sqrt(p)); long long mi = inv(pow_mod(a, m, p), p); long long aj = b; for(int j = 0;j < m;j++) { int i; for(i = 0;i < m;i++) { if(aj == prime[i]) { return i + j * m; } } aj = aj * mi % p; } return -1; } long long gcd(long long a, long long b) { return b == 0 ? a : gcd(b, a % b); } long long get_order(long long a, long long p) { long long phi = p - 1; long long tmp = phi; for(int i = 2;i * i <= tmp;i++) { if(tmp % i == 0) { while(tmp % i == 0) { tmp /= i; } long long t = pow_mod(a, phi / i, p); if(t == 1) { phi /= i; } while(t == 1) { t = pow_mod(a, phi / i, p); phi /= i; } } } if(tmp > 1) { long long t = pow_mod(a, phi / tmp, p); if(t == 1) { phi /= tmp; } while(t == 1) { t = pow_mod(a, phi / tmp, p); phi /= tmp; } } return phi; } long long crt(long long a1, long long p1, long long a2, long long p2) { long long x, y; exgcd(p1, p2, x, y); return (a1 * p2 * y % (p1 * p2) + a2 * p1 * x % (p1 * p2)) % (p1 * p2); } long long pohlig_hellman(long long a, long long b, long long p) { long long ord = get_order(a, p); long long m = ceil(sqrt(ord)); long long t = 1; for(int i = 0;i < m;i++) { t = t * a % p; } long long invt = inv(t, p); long long aj = b; for(int j = 0;j < m;j++) { int i; for(i = 0;i < m;i++) { if(aj == pow_mod(a, i, p)) { break; } } aj = aj * invt % p; if(i < m) { return j * m + i; } } long long x = 0; long long pp[100], aa[100]; int cnt = 0; for(int k = 2;k <= p;k++) { if(p % k == 0) { pp[++cnt] = 1; int tmp = p; while(tmp % k == 0) { tmp /= k; pp[cnt] *= k; } long long aa1 = pow_mod(a, ord / pp[cnt], p); long long bb1 = pow_mod(b, ord / pp[cnt], p); long long aj1 = 1; for(int j = 0;j < pp[cnt];j++) { if(aj1 == bb1) { x += (long long)j * pp[cnt] / pp[cnt - 1] * crt(1, pp[cnt - 1], aa[cnt - 1], pp[cnt - 1]); break; } aj1 = aj1 * aa1 % p; } aa[cnt] = aa1; } } return x % ord; } int main() { get_prime(100000); long long a, b, p; scanf("%lld%lld%lld", &a, &b, &p); printf("%lld\n", pohlig_hellman(a, b, p)); return 0; } ``` 注:在使用该代码时,需要输入三个参数a、b、p,其中a和p分别表示离散对数的底数和模数,b表示要离散对数

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值