前驅知識:
離散對數問題
離散對數
百度百科介紹:
在整數中,離散對數(英語:Discrete logarithm)是一種基於同餘運算和原根的一種對數運算。而在實數中對數的定義 logba是指對於給定的a和b,有一個數x,使得bx=a。相同地在任何羣G中可爲所有整數k定義一個冪數爲bx,而離散對數logba是指使得bx=a的整數k。 [2]
離散對數在一些特殊情況下可以快速計算。然而,通常沒有具非常效率的方法來計算它們。公鑰密碼學中幾個重要算法的基礎,是假設尋找離散對數的問題解,在仔細選擇過的羣中,並不存在有效率的求解算法。
詳細定義見 現代密碼學第四版(楊波編注)
測試:
- 離散對數問題: 已知1<g<p(g爲原根) ,1<y<p,求x使得y=gx mod p
- x^k=c mod p? 已知c, k, p, 如何求解
-
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則進行分組) . 隨機選整數k,1< k<p-1
計算密文對: C = {C1,C2}, 發送給接收者.
C1≡gk mod p, C2≡ykM mod p.
參數選取:
(1) 參數g和p可以全網公用,也可一人一套;
(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,這裏?−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) ? 從0 到 ?−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)