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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章