更新hill密码
上一次的hill密码只能使用三阶密钥矩阵,后面发现了2阶矩阵求逆矩阵不正确,原因在于求代数余子式时出了错,这里更新一下代码
import numpy as np
# 输入矩阵并判断是否存在逆矩阵
def inputMatrix():
while True:
# 输入一行、作为行列式的阶数和行列式的第一行
rank = list(input("").split())
matrix = [[0] * len(rank) for i in range(len(rank))]
matrix[0] = rank
# 输入行列式剩余数据
for i in range(1, len(matrix)):
matrix[i] = list(input("").split())
# 判断每一行输入是否合法
if len(matrix[i]) != len(matrix):
print("输入有误,重新输入。")
continue
# 转换字符型为整型
for i in range(len(matrix)):
matrix[i] = list(map(lambda x: int(x), matrix[i]))
# 判断是否存在逆矩阵
if not judgeInverse(matrix):
print("矩阵不存在逆矩阵,重新输入。")
continue
return matrix
def gcd(a,b): # 最大公约数
while b>0:
rem=a%b
a=b
b=rem
return a
# 判断是否存在逆元
def judgeInverse(matrix):
det = np.mat(matrix)
D = round(np.linalg.det(det)) # 行列式值
if gcd(D, 26)==1:
return True
return False
# 计算代数余子式
def alge_comple(matrix,i,j):
l=len(matrix)
# D = int(np.linalg.det(det))
import copy
matrix_ij=copy.deepcopy(matrix)
for a in range(0,len(matrix_ij)):
matrix_ij[a].pop(j)
matrix_ij.pop(i)
det = np.mat(matrix_ij)
Mij = round(np.linalg.det(det))
Aij=(-1)**(i+j)*Mij
# Aij1=matrix[(i+1)%len(matrix)][(j+1)%len(matrix)]*matrix[(i+2)%len(matrix)][(j+2)%len(matrix)]
# Aij2=matrix[(i+1)%len(matrix)][(j+2)%len(matrix)]*matrix[(i+2)%len(matrix)][(j+1)%len(matrix)]
# Aij=Aij1-Aij2
return Aij
# 生成密钥(矩阵的逆矩阵)
def createMatrixInverse(matrix):
# 计算行列式值的模逆D-invert
det = np.mat(matrix) # 矩阵
D = int(np.linalg.det(det)) # 行列式值
for i in range(26):
if (i*D-1)%26==0:
D_invert=i
break
matrix_inverse=[]
# Aij=(-1)^(i+j)|余子式|
# Aij*D_invert%26每个位置的元素
for i in range(len(matrix)):
tmp=[] # 每一行的元素
for j in range(len(matrix)):
Aij=alge_comple(matrix,i,j)
tmp.append((Aij*D_invert)%26)
matrix_inverse.append(tmp)
Matrix_inverse=np.matrix.tolist(np.matrix(matrix_inverse).T) # 先转置,再转化为列表
return Matrix_inverse
# 生成消息分组
def createMassageList(massage, matrix):
matrixRank = len(matrix)
massageList = []
for i in range(0, len(massage), matrixRank):
massageList.append(massage[i:i + matrixRank])
return massageList
# 字母序列转化为数字
def letterToDigit(massageList):
massageDigitList = [] # 替换后的数字列表
letterList = [] # 字母列表
for i in range(ord("a"), ord("z") + 1):
letterList.append(chr(i))
for massage in massageList:
listTmp = []
for i in range(len(massage)):
listTmp.append(letterList.index(massage[i]))
massageDigitList.append(listTmp)
return massageDigitList
# 数字序列转化为字母
def digitToLetter(massageList):
massageLetterList = [] # 还原后的字母列表
letterList = []
for i in range(ord("a"), ord("z") + 1):
letterList.append(chr(i))
# 替换数字为字母
for massage in massageList:
massageLetterList.append(letterList[massage % 26])
return massageLetterList
# 加密
def encrypt(massage, matrix):
ciphertextList = [] # 加密结果列表
massageList = createMassageList(massage, matrix)
massageDigitList = letterToDigit(massageList)
# 矩阵相乘
for massageDigit in massageDigitList:
for i in range(len(massageDigit)):
sum = 0
for j in range(len(massageDigit)):
sum += massageDigit[j] * matrix[j][i % len(matrix)]
ciphertextList.append(sum % 26)
CiphertextList=digitToLetter(ciphertextList)
return CiphertextList
# 解密
def decrypt(massage, matrix):
plaintextList = [] # 解密结果列表
matrix_inverse = createMatrixInverse(matrix)
massageList = createMassageList(massage, matrix)
massageDigitList=letterToDigit(massageList)
# 矩阵相乘
for msg in massageDigitList:
for i in range(len(msg)):
sum = 0
for j in range(len(msg)):
sum += msg[j] * matrix_inverse[j][i % len(matrix)]
plaintextList.append(sum % 26)
plaintextList = digitToLetter(plaintextList) # 数字转换为字母
plaintext = ""
for item in plaintextList:
plaintext += item
return plaintext
if __name__ == "__main__":
while True:
print("—————希尔密码—————")
choice = input("1、加密 2、解密 0、退出\n请选择:")
if choice == "1":
print("输入矩阵:")
matrix = inputMatrix()
massage = input("输入msg:")
massageList = createMassageList(massage, matrix)
ciphertextList = encrypt(massage, matrix)
secr=''.join(ciphertextList)
print("加密结果:", secr)
elif choice == "2":
massag = list(input("输入密文:"))
Massag = [str(i) for i in massag]
massageList = list(Massag)
print("输入矩阵:")
matrix = inputMatrix()
matrix_inverse = createMatrixInverse(matrix)
print("逆矩阵:")
for item in matrix_inverse:
print(item)
plaintext = decrypt(massageList, matrix)
print("解密结果:", plaintext)
else:
break
思路和上次差不多,只不过在计算代数余子式那里改变了方法,这次是将需要求代数余子式的位置对应的行列删除之后形成新的矩阵,并计算行列式的值,从而得到代数余子式,还有其中计算矩阵值时,得到的是一个浮点数,我们需要用round()将浮点数四舍五入