个人理解拼凑出来的:
'''求本原元'''
# 用辗转相除求最大公因子
def gcd(a, b):
r = a % b
while r != 0:
a = b
b = r
r = a % b
return b
# 欧拉函数
def euler(a):
cnt = 0
for i in range(1, a):
if gcd(a, i) == 1:
cnt += 1
return cnt
# 阶
def order(a, n, b):
# 输出b在mod(a)中的阶
# n是mod(a)群的阶
p = 1
while p <= n and b ** p % a != 1:
p += 1
if p <= n:
return p
else:
return -1
# 求本原元
def primitive_root(a):
n = euler(a)
for b in range(2, a):
if order(a, n, b) == n:
return b
import random
from math import pow
from Crypto.Util import *
# 扩展欧几里得求逆元
def exgcd(a, b):
if b == 0:
return 1, 0, a
else:
x, y, q = exgcd(b, a % b)
x, y = y, (x - (a // b) * y)
return x, y, q
# 扩展欧几里得求逆元
def ModReverse(a,p):
x, y, q = exgcd(a,p)
if q != 1:
raise Exception("No solution.")
else:
return (x + p) % p #防止负数
def encrypt(a, k, y, p):
xa = int(input('请输入加密的数据:'))
y1 = (a**k)%p
y2 = xa*(y**k) % p
return y1, y2
def decrypt(y1, y2, d, p):
#x= y2 / (y1**d) % p #是求逆元的过程
j = ModReverse(y1,y2)
x = (y2 * j) % p
return x
def main():
p = int(input('请选择一个大素数p:')) # 大素数
a = primitive_root(p) # 模p的原根a
print("原根a=", a) # p为37 可以看到,是2
#d = random.randint(2, 10) #产生随机常数d作为密钥
d = 5
y = (a ** d) % p #计算y
print(y)
#k = random.randint(2, 10) #随机数k=7
k=7
y1, y2 = encrypt(a, k, y, p)
x = decrypt(y1, y2, d, p)
print(f"ALice的公钥:\np = {p}\na = {a}\n密文(y1, y2) = ({y1},{y2})\n解密明文x = {x}")
if __name__ == '__main__':
main()
按照解释1的思路运行,选定37加密29是正确的,第三步解密 求x公式有误(开始没理解)(后来改进是求逆元的过程),固定随机数K和d加密正确,但是加密其他数字又出错了???跪求改正!!!
解释1:
解释2:
解释3:
解释4:
另一个解释很详细的文章链接:
ElGamal加密算法|ElGamal签名算法|公钥密码|数字签名|密码学|信息安全_Suryxin.的博客-CSDN博客
————————————————
其中原根:
本原元
当a模n的阶为φ(n),也就是说当且仅当x是φ(n)的倍数,使得ax ≡1(mod n)成立,此时称a为n的本原元。举个例子:
这些余数构成了一个模7的完全剩余系1,2,3,4,5,6,也就是对于任意a,都可以找到x0使得:
5x0 ≡a (mod 7)。
本原元求解Python:
# 用辗转相除求最大公因子
def gcd(a, b):
r = a % b
while r != 0:
a = b
b = r
r = a % b
return b
# 欧拉函数
def euler(a):
cnt = 0
for i in range(1, a):
if gcd(a, i) == 1:
cnt += 1
return cnt
# 阶
def order(a, n, b):
# 输出b在mod(a)中的阶
# n是mod(a)群的阶
p = 1
while p <= n and b ** p % a != 1:
p += 1
if p <= n:
return p
else:
return -1
# 求本原元
def primitive_root(a):
n = euler(a)
for b in range(2, a):
if order(a, n, b) == n:
return b
print(primitive_root(37))
# 可以看到,是2
其中求逆元:
# 扩展欧几里得求逆元
def exgcd(a, b):
if b == 0:
return 1, 0, a
else:
x, y, q = exgcd(b, a % b)
x, y = y, (x - (a // b) * y)
return x, y, q
# 扩展欧几里得求逆元
def ModReverse(a,p):
x, y, q = exgcd(a,p)
if q != 1:
raise Exception("No solution.")
else:
return (x + p) % p #防止负数
def main():
j = ModReverse(17,33)
print(j) #结果为2
if __name__ == '__main__':
main()
参考实现代码:
————————————————
文章链接:ElGamal公钥密码算法(Python实现)_elgamal python_忆往昔ོ 的博客-CSDN博客
from random import randint
import sympy
import sys
sys.setrecursionlimit(10000)
def fastExpMod(a, e, m):
a = a % m
res = 1
while e != 0:
if e & 1:
res = (res * a) % m
e >>= 1
a = (a * a) % m
return res
def primitive_element(p, q):
while True:
g = randint(2, p - 2)
if fastExpMod(g, 2, p) != 1 and fastExpMod(g, q, p) != 1:
return g
def e_gcd(a, b):
if b == 0:
return a, 1, 0
g, x, y = e_gcd(b, a % b)
return g, y, x - a // b * y
def encrypt(p, g, y, m):
while True:
k = randint(2, p - 2)
if e_gcd(k, p - 1)[0]:
break
c1 = fastExpMod(g, k, p)
c2 = (m * fastExpMod(y, k, p)) % p
return c1, c2
def decrypt(c1, c2, p, a):
v = fastExpMod(c1, a, p)
v_1 = e_gcd(v, p)[1]
m_d = c2 * v_1 % p
return m_d
def main():
# 这里的路径:读者自己电脑测试文件存放的正确路径
#m = int(open("F:\密码学实验\secret2.txt").readline())
m = int(input('输入一个数用于加密:'))
while True:
q = sympy.randprime(10 ** 149, 10 ** 150 / 2 - 1)
if sympy.isprime(q):
p = 2 * q + 1
if len(str(p)) == 150 and sympy.isprime(p):
break
g = primitive_element(p, q)
a = randint(2, p - 2)
y = fastExpMod(g, a, p)
c1, c2 = encrypt(p, g, y, m)
m_d = decrypt(c1, c2, p, a)
if m == m_d:
print("解密结果与明文相同!解密正确!")
else:
print("解密结果与明文不同!解密不正确!")
return m, p, g, y, c1, c2, m_d
if __name__ == '__main__':
print("m = %d\nALice的公钥:\np = %d\ng = %d\ng^a = %d\n密文(C1, C2) = (%d,\n%d)\n明文m = %d"
% main())
————————————————
文章链接:Python实现ElGamal加密算法_elgamal算法python_出门左拐是海的博客-CSDN博客
import random
from math import pow
a = random.randint(2, 10) #产生小于p的随机常数a
# 用辗转相除求最大公因子
def gcd(a, b):
if a < b:
return gcd(b, a)
elif a % b == 0:
return b;
else:
return gcd(b, a % b)
# 生成大量随机数
def gen_key(q):
key = random.randint(pow(10, 20), q)
while gcd(q, key) != 1:
key = random.randint(pow(10, 20), q)
return key
# 模幂运算
def power(a, b, c):
x = 1
y = a
while b > 0:
if b % 2 == 0:
x = (x * y) % c;
y = (y * y) % c
b = int(b / 2)
return x % c
# 非对称加密
def encrypt(msg, p, h, r):
en_msg = []
b = gen_key(p) # 得b
K = power(h, b, p)#K=(Sa)^b mod p
C1 = power(r, b, p) #C1=Sb=r^b mod p
for i in range(0, len(msg)):
en_msg.append(msg[i])
print("C1 : ", C1)
# print("(Sa)^b mod p used : ", K)
for i in range(0, len(en_msg)):
en_msg[i] = K * ord(en_msg[i])
print("C2 : ", en_msg)
return en_msg, C1
#解密
def decrypt(C2, C1, a, p):
dr_msg = []
h = power(C1, a, p)
for i in range(0, len(C2)):
dr_msg.append(chr(int(C2[i] / h)))
return dr_msg
# Driver code
def main():
msg =input('请输入加密数据:') # 共125位数字,1000bit
print("明文 :", msg)
p = random.randint(pow(10, 20), pow(10, 50)) # 获得大素数q
r = random.randint(2, p)#得r
a = gen_key(p) # 接收器的私钥
h = power(r, a, p)
C2, C1 = encrypt(msg, p, h, r)
dr_msg = decrypt(C2, C1, a, p)
dmsg = ''.join(dr_msg)
print("解密后文 :", dmsg);
if __name__ == '__main__':
main()