百度百科介绍:
在整数中,离散对数(英语:Discrete logarithm)是一种基于同余运算和原根的一种对数运算。而在实数中对数的定义 logba是指对于给定的a和b,有一个数x,使得bx=a。相同地在任何群G中可为所有整数k定义一个幂数为bx,而离散对数logba是指使得bx=a的整数k。 [2]
离散对数在一些特殊情况下可以快速计算。然而,通常没有具非常效率的方法来计算它们。公钥密码学中几个重要算法的基础,是假设寻找离散对数的问题解,在仔细选择过的群中,并不存在有效率的求解算法。
详细定义见 现代密码学第四版(杨波编注)
测试:
p= 276297763524605454993173661243865038299
及原根 g=2;
y=2x=221634578126418725062848422909836271381 mod p.
求x (答案为:3281483258849663070761913167 )
通过上述测试则可以继续查看下面内容
密钥产生过程:
– 首先产生一大素数p, 产生原根g和小于p的随机数x,计算y≡gx mod p,以(y, g, p)作为公开密钥,x作为秘密密钥.
加密过程:
设欲加密明文消息为M(如果M长度超过p则进行分组) . 随机选整数k,1< k
计算密文对: 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的对比:
最为简单的求解DLP的方法是连续计算?0, ?1, ?2,. . . ,直到得到?。这一方法需要O(?−1)次乘法,这里 ?−1是?的阶,因此,当?取足够大的值时,这不是有效方法(这恰好是密码关注的情形)。最为简单的求解"DLP" 的方法是连续计算g^0,
g^1, g^2,". . . ",直到得到y。这一方法需要O(p-1)次乘法,这里 p-1是g的阶,因此,当p取足够大的值时,这不是有效方法(这恰好是密码关注的情形)。
令?=?−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) 。
指数积分算法是目前已知最有力的计算离散对数方法。这项技术并不能应用于所有群,但是,一旦可以使用,算法为亚指数时间复杂度。指数积分算法可以应用于有限乘法群 ??∗。指数积分算法需要选择一个相对较小在??∗中的元集合? ,称之为分解基。这种方法中,??∗中大的元可以有效表示为集合?上元的乘积。指数积分算法是目前已知最有力的计算离散对数方法。这项技术并不能应用于所有群,但是,一旦可以使用,算法为亚指数时间复杂度。指数积分算法可以应用于有限乘法群 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)