我是Python的新手,我正在尝试将Hill Cipher作为一个小项目来实现。我想我已经找到了逻辑并且已经有加密部分工作,但是,在解密部分,我遇到了麻烦。特别是模数运算符。在下面的解密函数中,最后一行的第二个是给出麻烦的。
import numpy as np
import fractions as fr
def decrypt(matrix, words):
matrix=np.asmatrix(matrix)
length = len(matrix)
det_matrix=int(round((np.linalg.det(matrix))%26))
mult_inv=(abs(det_matrix*26)/fr.gcd(det_matrix,26))/26
matrix_inv=(((np.linalg.inv(matrix)*np.linalg.det(matrix))%26)*mult_inv)%26
words = words.lower()
arr = np.array([ord(i) - ord('a') for i in words], dtype=int)
decrypt_matrix=(np.asmatrix(matrix_inv)*(np.asmatrix(arr).transpose()))%26
return decrypt_matrix
我对解密功能的输入是:
>>> matrix
[[6, 24, 1], [13, 16, 10], [20, 17, 15]]
>>> words
'poh'
在计算det_matrix
之后,mult_inv
变量将具有值25.因此,计算matrix_inv
的代码行将具有以下值(这绝对正确) :
>>> matrix_inv
array([[ 8., 5., 10.],
[ 21., 8., 21.],
[ 21., 12., 8.]])
数组arr
将具有值:
>>> arr
array([15, 14, 7])
现在问题是下一行代码,在执行模数表达式
之前matrix_inv*(np.asmatrix(arr).transpose())
是:
matrix([[ 260.],
[ 574.],
[ 539.]])
现在,如果我在上面的矩阵上执行模数26,我应该将输出作为
([[0.],[2.],[19.]])
但是,下面是我执行表达式
时得到的结果>>> (np.asmatrix(matrix_inv)*(np.asmatrix(arr).transpose()))%26
matrix([[ 26.],
[ 2.],
[ 19.]])
我不明白为什么第一个元素的计算不正确(260%26是0而不是26)!但是,其余两个元素已正确计算!
非常感谢任何帮助!
P.S:我试过在版本2.7.11和3.6.1上运行代码。两者都不起作用。
答案 0 :(得分:0)
在Python 3.5,Spyder Python 3.5.2 |Anaconda custom (64-bit)| (default, Jul 5 2016, 11:41:13) [MSC v.1900 64 bit (AMD64)] on win32
matrix_inv = np.array([[ 8., 5., 10.],
[ 21., 8., 21.],
[ 21., 12., 8.]])
matrix_inv
Out[182]:
array([[ 8., 5., 10.],
[ 21., 8., 21.],
[ 21., 12., 8.]])
arr = np.array([15, 14, 7])
arr
Out[184]: array([15, 14, 7])
(np.asmatrix(matrix_inv)*(np.asmatrix(arr).transpose()))%26
Out[185]:
matrix([[ 0.],
[ 2.],
[ 19.]])
print(np.__version__)
1.11.1
答案 1 :(得分:0)
问题是det
是numpy.float64
。你得到的可能是:
round(259.6 % 26) # -> round(25.600000000000023) -> 26.0
这有效:
round(259.6) % 26 # 0
在您的解密结果中:
dec = decrypt(matrix, words)
dec[0,0] # 25.999999999989768
dec[0,0] % 26 # 25.999999999989768
它只会显示为26.
因为我对3x3矩阵的模块化逆转感兴趣,所以我写了一些代码......也许这对你有用......
import numpy as np
from itertools import product, cycle
def gcd_xy(a, b):
'''
extended euclidean algo: return (g, x, y): g = gcd(a, b); a*x + b*y = d.
'''
q, r = divmod(a, b)
x, y, x1, y1 = 0, 1, 1, 0
while r != 0:
x1, y1, x, y = x, y, x1 - q*x, y1 - q*y
b, (q, r) = r, divmod(b, r)
return b, x, y
def mod_inv(e, n):
'''
return d == 1/e mod n or raise ValueError if e and n are not co-prime.
'''
g, d, _ = gcd_xy(e, n)
if g != 1:
msg = '{} has no inverse mod {}'.format(e, n)
raise ValueError(msg)
d %= n
return d
def mod_inv_matrix(matrix, n):
'''
modular inverse of 3x3 matrix
'''
inv = np.zeros((3, 3), dtype=int)
det = round(np.linalg.det(matrix))
det_inv = mod_inv(det, n)
matrixT = matrix.T
for (i, j), sign in zip(product(range(3), repeat=2), cycle((1, -1))):
m = np.delete(np.delete(matrixT, i, axis=0), j, axis=1)
inv[i, j] = sign * det_inv * round(np.linalg.det(m)) % n
return inv
def hill_decrypt(matrix, words):
matrix_inv = mod_inv_matrix(matrix, n=26)
words = words.lower()
arr = np.array([ord(i) - ord('a') for i in words], dtype=int)
plain = (matrix_inv @ arr) % 26
return plain
matrix = np.array([[6, 24, 1], [13, 16, 10], [20, 17, 15]], dtype=int)
words = 'poh'
dec = hill_decrypt(matrix, words)
print(dec)
对于模块化逆,您也可以使用gmpy
module
import gmpy
gmpy.invert(7, 26)