密码学硬核笔记——特殊离散对数问题

最喜欢的lora

前言

前几天参加了网鼎杯的比赛,第一道题就是简单粗暴的离散对数问题(DLP)。当时自己是用sagemath的discrete_log()函数的直接秒解的(另外第三题必须要用cmd打开flag才出来就很坑)。赛后发现这道离散对数题应该是用Pohlig–Hellman algorithm 做的,所以针对这次的题目学习了一遍该算法。


  • 定义6.7:设 H H H是群 G G G的一个子集合,如果对于群 G G G的二元运算, H H H也构成一个群,就称 H H H为群 G G G子群,记作 H ≤ G H ≤ G HG
  • 定义6.8: 若群 G G G包含的元素个数有限,则称 G G G有限群,否则称为无限群。有限群 G G G所包含的元素个数称为 G G G,记为 ∣ G ∣ | G | G
  • 定义6.9 :设 a a a是群 G G G中的一个元素,若存在正整数 n n n使得 a n = e a^n = e an=e,则称 a a a为有限阶元素,满足 a n = e a^n = e an=e的最小正整数 n n n叫做 a a a,记为 ∣ a ∣ | a | a。若不存在正整数 n n n使得 a n = e a^n = e an=e,则称 a a a为无限阶元素。
  • 定义6.10 设 G G G为群,若存在 G G G的一个元素 a a a,使得 G G G中的任意元素均由 a a a的幂组成,即
    G = { a n ∣ n ∈ Z } G = \{ a^n | n ∈ Z\} G={annZ}
    则称群 G G G循环群,元素 a a a为循环群 G G G的生成元,记为 G = < a > G = < a > G=<a>

后面的内容都是围绕循环群的子群以及群和元素的阶展开的。


Pohlig–Hellman algorithm

维基百科解释如下:is a special-purpose algorithm for computing discrete logarithms in a finite abelian group whose order is a smooth integer.
是一种特殊算法,在阶为光滑数的有限阿贝尔群上解决离散对数问题。

同时

先看普遍情况下的算法:
在这里插入图片描述

大致流程如下:
(假设阶为 ϕ ( m ) \phi(m) ϕ(m))

首先,要解决的问题是
g x ≡ h   m o d   m   a n d   n = ϕ ( m ) = ∏ i = 1 r p i e i g^x\equiv h \ mod\ m\ and\ n=\phi(m)=\prod_{i=1}^r p_i ^ {e_i} gxh mod m and n=ϕ(m)=i=1rpiei

等式两边同乘上一个指数 n p i e i \frac{n}{p_i ^ {e_i}} piein,可以得到:
{ ( g x 1 ) n p 1 e 1 ≡ h n p 1 e 1   m o d   m ( g x 2 ) n p 2 e 2 ≡ h n p 2 e 2   m o d   m ( g x 3 ) n p 3 e 3 ≡ h n p 3 e 3   m o d   m . . . ( g x r ) n p r e r ≡ h n p r e r   m o d   m \begin{cases} (g^{x_1})^\frac{n}{p_1 ^ {e_1}}\equiv h^\frac{n}{p_1 ^ {e_1}} \ mod\ m\\ (g^{x_2})^\frac{n}{p_2 ^ {e_2}}\equiv h^\frac{n}{p_2 ^ {e_2}} \ mod\ m\\ (g^{x_3})^\frac{n}{p_3 ^ {e_3}}\equiv h^\frac{n}{p_3 ^ {e_3}} \ mod\ m\\ ...\\ (g^{x_r})^\frac{n}{p_r ^ {e_r}}\equiv h^\frac{n}{p_r ^ {e_r}} \ mod\ m\\ \end{cases} gx1)p1e1nhp1e1n mod mgx2)p2e2nhp2e2n mod mgx3)p3e3nhp3e3n mod m...gxr)prernhprern mod m

对于每一条式子来说,通过遍历 x i ∈ { 0 , 1 , . . . , p i e i } x_i\in\{0,1,...,p_i ^ {e_i}\} xi{0,1,...,piei}一定可以计算出一个 x i x_i xi满足: ( g x i ) n p i e i ≡ h n p i e i   m o d   m (g^{x_i})^\frac{n}{p_i ^ {e_i}}\equiv h^\frac{n}{p_i ^ {e_i}} \ mod\ m gxi)pieinhpiein mod m

所以我们可以得到:

{ x ≡ x 1   m o d    p 1 e 1 x ≡ x 2   m o d    p 2 e 2 x ≡ x 3   m o d    p 3 e 3 . . . x ≡ x r   m o d    p r e r \begin{cases} x\equiv x_1 \ \mod p_1 ^ {e_1}\\ x\equiv x_2 \ \mod p_2 ^ {e_2}\\ x\equiv x_3 \ \mod p_3 ^ {e_3}\\ ...\\ x\equiv x_r \ \mod p_r ^ {e_r}\\ \end{cases} xx1 modp1e1xx2 modp2e2xx3 modp3e3...xxr modprer

最后用中国剩余定理可以算出最后的 x x x
x ≡ x ′ m o d    ∏ i = 1 r p i e i x \equiv x' \mod \prod_{i=1}^r p_i ^ {e_i} xxmodi=1rpiei


理论依据

(为什么能算出这个 x i x_i xi?)

我们用群理论重新梳理一遍整个算法。

根据题目内容,我们可以构建生成元为 g g g ,阶为 ϕ ( m ) \phi(m) ϕ(m)(用n表示),模 m m m的有限循环群
群内元素为:
G = { 1 , g 1 , g 2 , . . . , g n } G=\{1,g^1,g^2,...,g^n\} G={1,g1,g2,...,gn}
(这里先讲一下,循环群的阶与生成元的阶是一样的,暂且认为阶为 n n n,因为根据欧拉定理 g ϕ ( m ) ≡ 1 m o d    m g^{\phi(m)}\equiv1 \mod m gϕ(m)1modm,即使存在元素的阶t小于 n n n(即 g t ≡ 1 m o d    m g^{t}\equiv1 \mod m gt1modm),那也是 n n n的因子,可以通过遍历因子的方式得到 t t t

通过这个循环群我们可以知道 h h h是在该群中的,而且 x ∈ { 0 , 1 , . . , n − 1 } x\in\{0,1,..,n-1\} x{0,1,..,n1}

那为什么要乘上指数呢?
其实对每个式子乘上指数是为了构造多个不同的该循环群的子群。

g i = g n p i e i g_i=g^\frac{n}{pi^{e_i}} gi=gpiein,可以构造一个 g i g_i gi为生成元,阶为 p i e i p_i^{e_i} piei的循环群子群
元素为
< g i > = { 1 , g n p i e i , g n p i e i ∗ 2 , g n p i e i ∗ 3 , . . . , g n p i e i ∗ ( p i e i − 1 ) } <g_i>=\{1,g^\frac{n}{pi^{e_i}},g^{\frac{n}{pi^{e_i}}*2},g^{\frac{n}{pi^{e_i}}*3},...,g^{\frac{n}{pi^{e_i}}*(p_i^{e_i}-1)}\} <gi>={1,gpiein,gpiein2,gpiein3,...,gpiein(piei1)}

同时我们也构造 h i = h n p i e i = ( g x ) n p i e i m o d    m h_i=h^{\frac{n}{pi^{e_i}}}=(g^{x})^{\frac{n}{pi^{e_i}}} \mod m hi=hpiein=(gx)pieinmodm(取模后 x x x变成了 x i x_i xi
因此 h i ∈ < g i > h_i\in <g_i> hi∈<gi>, x i x_i xi必定存在,我们可以通过遍历 x i ∈ [ 0 , p i e i − 1 ] x_i\in [0,p_i^{e_i}-1] xi[0,piei1]找到它。

同时我们要关注 g x ≡ h   m o d   m → ( g n p i e i ) x i ≡ h n p i e i   m o d   m g^x\equiv h \ mod\ m\rightarrow (g^{\frac{n}{p_i^{e_i}}})^{x_i}\equiv h^\frac{n}{p_i ^ {e_i}} \ mod\ m gxh mod m(gpiein)xihpiein mod m
实际上是
x ∈ [ 0 , n − 1 ] → x i ∈ [ 0 , p i e i − 1 ] x\in[0,n-1]\rightarrow x_i\in [0,p_i^{e_i}-1] x[0,n1]xi[0,piei1]
也就是说,每个等式计算出来的 x i x_i xi是原来的 x x x在不同模下的结果。所以我们才能用CRT把原来的 x x x算出来。


特殊算法(当阶为素数幂prime power):
在这里插入图片描述
其实就是普遍算法,为了美观代码简化了一点,差异不大。但可以与 B S G S BSGS BSGS算法并用(其实我并不太清楚怎么并用), 时间复杂度降为 O ( e p ) O(e\sqrt{p}) O(ep )


实战演练

you_rise_me_up.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from Crypto.Util.number import *
import random

n = 2 ** 512
m = random.randint(2, n-1) | 1
c = pow(m, bytes_to_long(flag), n)
print 'm = ' + str(m)
print 'c = ' + str(c)

# m = 391190709124527428959489662565274039318305952172936859403855079581402770986890308469084735451207885386318986881041563704825943945069343345307381099559075
# c = 6665851394203214245856789450723658632520816791621796775909766895233000234023642878786025644953797995373211308485605397024123180085924117610802485972584499

离散对数问题, n n n 2 512 2^{512} 2512,素数幂,可以使用Pohlig–Hellman algorithm。

首先找阶,因为生成元m的阶整除 ϕ ( n ) \phi(n) ϕ(n),所以我们可以通过遍历 2 2 2的幂来找到这个阶。
遍历之后发现阶为 2 510 2^{510} 2510,直接使用上述特殊算法就可得到结果。

(自己写的辣鸡代码)

def Prime_power_Pohlig_Hellman(g,h,n,p,e):
    '''
    phi(n)=p^e
    g^(p^e)=1 mod n
    g^x=h mod n
    '''
    for a in range(e):
        if(pow(g,2**a,n)==1):
            break
    x_k=0
    e=a
    gm=pow(g,pow(p,e-1,n),n)
    print gm
    if(pow(g,p**e,n)!=1):
        print 'error'
    for k in range(e):
        _x=pow(p,e,n)-x_k
        if(pow(g,x_k,n)*pow(g,_x,n)%n !=1 ):
            print 'error'
        h_k=pow(pow(g,_x,n)*h,pow(p,e-1-k,n),n)
        for d_k in range(p):
            if(pow(gm,d_k,n)==h_k):
                print k,d_k
                break

        x_k=x_k+d_k*pow(p,k,n)
        
    return x_k  

if __name__ =='__main__':
    n=2**512
    m = 391190709124527428959489662565274039318305952172936859403855079581402770986890308469084735451207885386318986881041563704825943945069343345307381099559075
    c = 6665851394203214245856789450723658632520816791621796775909766895233000234023642878786025644953797995373211308485605397024123180085924117610802485972584499
    print libnum.n2s(Prime_power_Pohlig_Hellman(m, c, 2**512, 2, 511) )   

最后得到
在这里插入图片描述


后记

这篇博客的内容是我第一次使用新学的群理论来分析(尽力了),可能有讲得不好的地方,请多多包涵。

个人体会有两个,一是其实算法并没有那么难看懂,英语也没有那么难读懂,莫名的恐惧只是因为不了解。所以多看几遍就好了。

二是我觉得了解算法就是一种说服自己的过程,这个算法为什么要这样做?理论依据又是什么?学习算法的过程中,我一直在寻找理由说服自己,这个算法这样做肯定是有它的理由的。可能有点吹毛求疵的感觉,但我只是想纯粹的去理解算法。

三是自己还有很大的进步空间。

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值