ElGamal 算法思考

前驱知识:

离散对数问题

离散对数

百度百科介绍:

整数中,离散对数(英语:Discrete logarithm)是一种基于同余运算和原根的一种对数运算。而在实数中对数的定义 logba是指对于给定的ab,有一个数x,使得bx=a。相同地在任何群G中可为所有整数k定义一个幂数为bx,而离散对数logba是指使得bx=a的整数k。 [2] 

离散对数在一些特殊情况下可以快速计算。然而,通常没有具非常效率的方法来计算它们。公钥密码学中几个重要算法的基础,是假设寻找离散对数的问题解,在仔细选择过的群中,并不存在有效率的求解算法。

详细定义见 现代密码学第四版(杨波编注)

测试:

  1. 离散对数问题: 已知1<g<p(g为原根) 1<y<p,求x使得y=gx mod p
  2. x^k=c mod p? 已知c, k, p, 如何求解
  3. p= 276297763524605454993173661243865038299

    及原根 g=2

    y=2x=221634578126418725062848422909836271381 mod p.

    x                                                                    (答案为:3281483258849663070761913167

 

 

通过上述测试则可以继续查看下面内容

 

主要内容:

ElGamal 算法问题及其思考

密钥产生过程

    首先产生一大素数p, 产生原根g和小于p的随机数x,计算y≡gx mod p,以(y, g, p)作为公开密钥,x作为秘密密钥.

加密过程

     设欲加密明文消息为M(如果M长度超过p则进行分组) . 随机选整数k1< k<p-1

计算密文对: C = {C1,C2}, 发送给接收者.

     C1≡gk mod p,   C2≡ykM mod p.   

参数选取

(1) 参数gp可以全网公用,也可一人一套;

       (2) 加密不同的明文分组时须选用独立的随机数k,但秘密的解密密钥d 可以长期不变.

       (3)通常将大素数p选为安全素数,即p=2q+1,且q为素数;

       (4)  p的位数应在1024比特以上;

 

例题1

Alice 要加密 M= “good” Bob:

            good=1735356260

首先得到 Bob的公开密钥 yB,选择随机 k= 55556855068253029573 计算:

K=2k= 2449332849913969723717932843268286 96205 mod p.

  计算密文对:  C1 = 168233921366350220394075 289481675258886 mod p C2=190728535576783591596526073857710412715 mod p.

发送 {C1,C2} 给Bob .      加密后:(good=676f6f64)

与RSA的对比

安全性分析

1.穷举攻击:

最为简单的求解DLP的方法是连续计算?0 ?1 ?2. . . ,直到得到?。这一方法需要O(?1)次乘法,这里 ?1?的阶,因此,当?足够大的值时,这不是有效方法(这恰好是密码关注的情形)最为简单的求解"DLP" 的方法是连续计算g^0,
g^1, g^2,". . . ",直到得到y。这一方法需要O(p-1)次乘法,这里 p-1是g的阶,因此,当p取足够大的值时,这不是有效方法(这恰好是密码关注的情形)。

2.小步大步算法:

?=?−1,这里??的阶。小步大步算法是对穷举搜索方法在效率和存储之间的平衡,它的基础是以下事实。如果? = ??,则 我们可以写 ?=??+?,这里 0  ? ? < ?。因此, ??  ?????,这意味着?(??)??? 这就给出如下计算 ?的方法。令m=⌈√(p-1)⌉,这里p-"1 " 是g的阶。

小步大步算法是对穷举搜索方法在效率和存储之间的平衡,它的基础是以下事实。如果β" = " g^x,则 我们可以写 x=i⋅m+j,这里" 0 "≤ i, j < m。因此, g^x  ≡ g^(i⋅m)⋅g^j,这意味着β(g^(-m) )^i≡g^j 。 这就给出如下计算 x的方法。

输入:生成元?的阶 ?1和元 ?输出: 离散对数 ?=log??(1) 设置?=?−1(2) 建立一个条目 (???)的表, 这里 0 ? < ?。以条目中      的第2项对表排序。(3) 计算?? 和设置?=?(4)  ?  ?−1 进行如下循环:(4.1)   检查  ?是否为表中某个第2 (4.2)   如果?  g? 则返回 (? = ?? + ?)(4.3)   设置  ??g?输入:生成元g的阶 p-1和元 β。
输出: 离散对数 x=log_g⁡β 。
(1) 设置m=⌈√(p-1)⌉。
(2) 建立一个条目 为(j,g^j)的表, 这里" 0 "≤j < m。以条目中
"      " 的第2项对表排序。
(3) 计算g^m  和设置γ=β。
(4)"  " i 从"0 " 到 m-1 进行如下循环:
("4.1")"   " 检查"  " γ是否为表中某个第2项 。
("4.2")"   " 如果γ ≡" " "g" ^j, 则返回 (x = i⋅m + j)。
("4.3")"   " 设置"  " γ≡γ⋅g^(-m) 。

空间和时间复杂度分析:

3.指数积分算法:

指数积分算法是目前已知最有力的计算离散对数方法。这项技术并不能应用于所有群,但是,一旦可以使用,算法为亚指数时间复杂度。指数积分算法可以应用于有限乘法群 ??指数积分算法需要选择一个相对较小在??中的元集合? ,称之为分解基。这种方法中,??中大的元可以有效表示为集合?上元的乘积。指数积分算法是目前已知最有力的计算离散对数方法。这项技术并不能应用于所有群,但是,一旦可以使用,算法为亚指数时间复杂度。指数积分算法可以应用于有限乘法群 Z_p^∗ 。指数积分算法需要选择一个相对较小在Z_p^∗ 中的元集合S ,称之为分解基。这种方法中,Z_p^∗ 中大的元可以有效表示为集合S上元的乘积。

 

 

题目与代码:

题目一:

p=26622572818608571599593915643850055101138771
{{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}}

g=65537, 
g^x=14632691854639937953996750549254161821338360 (mod p)
利用中国剩余定理求x;

代码一:

import math

#欧几里得算法求最大公约数

def get_gcd(a, b):

	k = a // b

	remainder = a % b

	while remainder != 0:

		a = b 

		b = remainder

		k = a // b

		remainder = a % b

	return b

	

#扩展欧几里得算法求线性方程的x与y

def get_(a, b):

	if b == 0:

		return 1, 0

	else:

		k = a // b

		remainder = a % b		

		x1, y1 = get_(b, remainder)

		x, y = y1, x1 - k * y1			

	return x, y

	

#计算逆元的函数,返回值是逆元
def answer(a,b):        
        #将初始b的绝对值进行保存
        if b < 0:
                m = abs(b)
        else:
                m = b
                flag = get_gcd(a, b)
                if flag == 1:	
                        x, y = get_(a, b)	
                        x0 = x % m #对于Python '%'就是求模运算,因此不需要'+m'
                        return x0
                else:
                        return("Do not have!")


def str_to_hex(s):
    return ' '.join([hex(ord(c)).replace('0x', '') for c in s])

def hex_to_str(s):
    return ''.join([chr(i) for i in [int(b, 16) for b in s.split(' ')]])
    
def str_to_bin(s):
    return ' '.join([bin(ord(c)).replace('0b', '') for c in s])
    
def bin_to_str(s):
    return ''.join([chr(i) for i in [int(b, 2) for b in s.split(' ')]])




def exGcd(a,b,xy):#求特解
    if b==0:
        xy[0]=1
        xy[1]=0
        #print ("(f, g) is ", a)
        return a
    r=exGcd(b,a%b,xy)
    t = xy[0]
    xy[0] = xy[1]
    xy[1]=t-a//b*xy[1]
    return r
#-----------------------------------------以下为求出密文的e次方---------------------------#




a=26622572818608571599593915643850055101138771
h=14632691854639937953996750549254161821338360
s=[[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]]

g=65537
x=1
n=[]#模数mi
e=[]#加密指数
c=[]#密文
hi=[]
gi=[]
r=len(s)

for i in s:
    for j in range(i[1]):
        x=x*i[0]
        n.append(i[0])
#print(x-(a-1))


for i in range(r):
    q=a//s[i][0]
    x=pow(g,q,a)
    gi.append(x)
for i in range(r):
    q=a//s[i][0]
    x=pow(h,q,a)
    hi.append(x)

for i in range(r):
    for j in range(0,s[i][0]-1):
        x=j
        t=pow(gi[i],x,a)
        if(t==hi[i]):
            c.append(x)
            break
        

print(c)
#print(hi)
#print(gi)
#print(len(c)-len(n))
    
    


Z=1#即是m
for i in range(r):
    Z=Z*n[i]  
#print(Z)

z=[]#保存的是每一项的ai*Mi*Mi'

for i in range(r):
    Mi=(Z//n[i])#即是Mi
    #print(Mi)
    x=(answer(Mi,int(n[i])))#求出 Mi'
    print(x)
    s=Mi*x
    #print(s)
    s=s*c[i]
    z.append(s)
    
ans=0#求和的结果
for i in z:
        ans=ans+i

p=ans%Z#即是密文的e次方
#a=e[0]#本题的加密指数为5
print(p)

'''#———————————————————————以下为大数开方(考虑牛顿迭代法)———————————————#


def five_e_root(x):
        if(x==0):
                return 0
        x0=x
        x1=(4*x0//5)+(x//(x0*x0*x0*x0*5))#迭代法求五次方根
        while(abs(x1-x0)>0.00001):#要求精度
                x0=x1
                x1=(4*x0//5)+(x//(x0*x0*x0*x0*5))
        return x1
                

#print(p)
p=five_e_root(p)
#print(p)#结果

p=hex(p)#转换为16进制
print(p)

        '''










        

 

题目二:

椭圆曲线是secp256k1
y^2 = x^3 + ax + b,其中 a = 0,b = 7
p = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F = 2 ^ 256 - 2 ^ 32 - 2 ^ 9 - 2 ^ 8 - 2 ^ 7 - 2 ^ 6 - 2 ^ 4 - 1 
点G的x和y座标分别为:
x=79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798    y=483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8

已知私钥为您的学号,求公钥

[115558381663906209150297993116070464229031829974553177032784681955324439750888, 84875200934012589315793426756669380005172249774350913639994928299122491983685]
 

#coding:utf-8
#欧几里得算法求最大公约数
def get_gcd(a, b):
    k = a // b
    remainder = a % b
    while remainder != 0:
        a = b 
        b = remainder
        k = a // b
        remainder = a % b
    return b
    
#改进欧几里得算法求线性方程的x与y
def get_(a, b):
    if b == 0:
        return 1, 0
    else:
        k = a // b
        remainder = a % b       
        x1, y1 = get_(b, remainder)
        x, y = y1, x1 - k * y1          
    return x, y

#返回乘法逆元
def yunsle(a,b):
    #将初始b的绝对值进行保存
    if b < 0:
        m = abs(b)
    else:
        m = b
    flag = get_gcd(a, b)

    #判断最大公约数是否为1,若不是则没有逆元
    if flag == 1:   
        x, y = get_(a, b)   
        x0 = x % m #对于Python '%'就是求模运算,因此不需要'+m'
    #print(x0) #x0就是所求的逆元
        return x0
    else:
        print("Do not have!")


mod=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
#print(mod)
#mod=23
a=0
b=7
G=[0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8]
#G=[3,10]
#次数
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#私钥k为您的学号
k=xxxxxxx
temp=G

def get_result2(tmp_list):
  P=tmp_list[0]
  for i in range(1,len(tmp_list)):
    Q=tmp_list[i]
    if P == Q:
        aaa=(3*pow(P[0],2) + a)
        bbb=(2*P[1])
        if aaa % bbb !=0:
            val=yunsle(bbb,mod)
            y=(aaa*val) % mod
        else:
            y=(aaa/bbb) % mod 
    else:
        aaa=(Q[1]-P[1])
        bbb=(Q[0]-P[0])
        if aaa % bbb !=0:
            val=yunsle(bbb,mod)
            y=(aaa*val) % mod
        else:
            y=(aaa/bbb) % mod
    Rx=(pow(y,2)-P[0] - Q[0])  % mod
    Ry=(y*(P[0]-Rx) - P[1])  % mod
    P=[Rx,Ry]
  return P


def jieguo(G,num):
    global list1
    temp=G
    i=2
    while(i*2<=num):
            aaa=(3*pow(temp[0],2) + a)
            bbb=(2*temp[1])
            if aaa % bbb !=0:
                val=yunsle(bbb,mod)
                y=(aaa*val) % mod
            else:
                y=(aaa/bbb) % mod
    
            Rx=(pow(y,2)-temp[0] - temp[0]) % mod
            Ry=(y*(temp[0]-Rx) - temp[1]) % mod
            temp=[Rx,Ry]
            i=i*2
    list1.append(temp)
    rest_num=num-i
    if rest_num!=0:
        jieguo(G,rest_num)


list1=[]
jieguo(G,k)
list1.append(G)
result=get_result2(list1)


print(result)




#print(temp)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章