Python实现Hill密码加密解密后无法还原原消息的问题排查
Hill密码解密失败问题修复
你的代码核心问题出在解密阶段的矩阵逆计算和乘法逻辑不匹配,以下是具体问题和修复方案:
问题分析
- 错误的逆矩阵计算:
np.linalg.inv(key_matrix) % 26会返回浮点矩阵,直接取模会导致精度丢失或错误的整数结果。Hill密码的逆矩阵必须是模26下的整数矩阵,需通过行列式的模逆和伴随矩阵计算。 - 加密解密乘法不对应:加密时你用行向量乘以密钥矩阵的转置,解密时需对应使用逆矩阵的转置进行乘法,否则无法还原原始消息。
修复后的完整代码
import numpy as np def encrypt(message, key): message = message.upper() key = key.upper() # 生成3x3密钥矩阵 key_matrix = np.array([list(map(lambda x: ord(x) % 65, key[i:i+3])) for i in range(0, len(key), 3)], dtype=int) # 填充消息至3的倍数 message += 'X' * (3 - len(message) % 3) if len(message) % 3 != 0 else '' cipher_text = '' for i in range(0, len(message), 3): # 生成行向量 message_vector = np.array(list(map(lambda x: ord(x) % 65, message[i:i+3])), dtype=int) # 行向量 × 密钥矩阵转置 → 密文向量 cipher_vector = np.dot(message_vector, key_matrix.T) % 26 cipher_text += ''.join(chr(c + 65) for c in cipher_vector) print("Ciphertext:", cipher_text) return cipher_text def modinv(a, m): # 扩展欧几里得算法求模逆 m0, x0, x1 = m, 0, 1 while a > 1: q = a // m m, a = a % m, m x0, x1 = x1 - q * x0, x0 return x1 + m0 if x1 < 0 else x1 def mod_matrix_inv(matrix, mod): # 计算模mod下的矩阵逆 n = matrix.shape[0] # 计算行列式 det = int(np.linalg.det(matrix)) # 求行列式的模逆(需保证det与mod互质) det_inv = modinv(det % mod, mod) # 计算伴随矩阵(余子式矩阵的转置) adjugate = np.linalg.inv(matrix) * det # 转换为整数并取模,再乘以行列式逆取模 inv_matrix = (det_inv * adjugate) % mod # 转换为整数矩阵(避免浮点残留) return inv_matrix.astype(int) def decrypt(cipher_text, key): cipher_text = cipher_text.upper() key = key.upper() key_matrix = np.array([list(map(lambda x: ord(x) % 65, key[i:i+3])) for i in range(0, len(key), 3)], dtype=int) # 计算模26下的密钥矩阵逆 key_matrix_inv = mod_matrix_inv(key_matrix, 26) plain_text = '' for i in range(0, len(cipher_text), 3): cipher_vector = np.array(list(map(lambda x: ord(x) % 65, cipher_text[i:i+3])), dtype=int) # 密文行向量 × 逆矩阵的转置 → 明文向量(对应加密时的转置操作) plain_vector = np.dot(cipher_vector, key_matrix_inv.T) % 26 plain_text += ''.join(chr(int(c) % 26 + 65) for c in plain_vector) print("Decrypted Text:", plain_text) return plain_text # 测试代码 def main(): message = "GFG" key = "GYBNQKURP" cipher_text = encrypt(message, key) decrypted_text = decrypt(cipher_text, key) if __name__ == "__main__": main()
测试结果
运行后输出:
Ciphertext: GKJ Decrypted Text: GFG
关键修改说明
- 新增
mod_matrix_inv函数,专门计算模26下的整数矩阵逆,解决浮点逆矩阵的精度问题。 - 解密时使用逆矩阵的转置进行乘法,与加密阶段的
key_matrix.T操作对应,保证还原逻辑一致。 - 所有矩阵和向量都指定
dtype=int,避免浮点运算带来的误差。
内容的提问来源于stack exchange,提问作者molly k
相关产品推荐
相关产品推荐

