message = '*****{********************}'
cipher = ''
其加密变换为:
E k ( m ) = ( m + k ) m o d q = c 0 ≤ m , c < q E_k(m) = (m+k)~mod~q = c\\ 0 \leq m,~cEk(m)=(m+k) mod q=c0≤m, c<q
密钥空间为 K = { k ∣ 0 ≤ k < q } K=\{k|0\leq kK={k∣0≤k<q}
,元素个数为q,当 k = 0 k=0 k=0 时,为恒等变换
其解密变换为:
D k ( c ) = ( c − k ) m o d q = m D_k(c)=(c-k)~mod~q=m Dk(c)=(c−k) mod q=m
key, _, _ = xgcd(24249125136394343, 16156191447296617)
key = key % 16156191447296617
key实为24249125136394343的逆元,可以采用扩展欧式算法得出
关于逆元:
设n为正整数,a为整数满足 0 < a < n 00<a<n
若存在一个正整数b, 0 < b < n 00<b<n 满足:
a b ( m o d n ) = 1 ab(mod~n)=1 ab(mod n)=1
称b为 a ( m o d n ) a(mod~n) a(mod n) 的逆元,并记b为 a − 1 ( m o d n ) a^{-1}(mod~n) a−1(mod n)
关于逆元使用扩欧算法计算:
若想求得满足 a x ( m o d n ) = 1 的逆元 x ,等价于 ax(mod~n)=1的逆元x,等价于 ax(mod n)=1的逆元x,等价于 a x = k n + 1 , k ax=kn+1,k ax=kn+1,k 为整数
移项得 a x − k n = 1 ax-kn=1 ax−kn=1 即
a x + l n = 1 ax+ln=1 ax+ln=1
可以发现求解逆元转化为扩欧算法计算x,但x可能为负,所以再次取模保证了 k e y > 0 key>0 key>0 (这是因为python的模运算会保证非负)
更多内容详见:https://zhuanlan.zhihu.com/p/449221995
关于扩欧算法:
关于AITMCLAB.libnum中所带扩欧算法函数,可直接import使用,其实现可自行查看
def xgcd(a, b):
"""
Extented Euclid GCD algorithm.
Return (x, y, g) : a * x + b * y = gcd(a, b) = g.
"""
pass
关于自己编写的Egcd()函数
def Egcd(a, b):
x = [a, 1, 0]
y = [b, 0, 1]
while y[0] != 0:
q = x[0]//y[0]
for i in range(0, 3):
x[i] = x[i] - q*y[i]
tmp = x[:]
x = y[:]
y = tmp[:]
return x
个人关于扩欧算法的理解:使用单位阵 I I I 将辗转相除法每一步所等价的初等矩阵 P i P_i Pi(左乘)的结果 P = P 1 P 2 . . . P t P=P_1P_2...P_t P=P1P2...Pt记录下来
[ a 1 0 b 0 1 ] − > [ r u v 0 m n ] 其中 P = [ u v m n ] \left[\begin{matrix} a&1&0\\ b&0&1 \end{matrix}\right] -> \left[\begin{matrix} r&u&v\\ 0&m&n \end{matrix}\right] \\其中~P= \left[\begin{matrix} u&v\\ m&n \end{matrix}\right] [ab1001]−>[r0umvn]其中 P=[umvn]
移位加密程序实现:
for char in message:
if 'a' <= char <= 'z':
now_cipher = (ord(char) - ord('a') + key) % 26
cipher += chr(now_cipher + ord('a'))
else:
cipher += char
最后再一次使用逆元进行计算(同key)得到了output
numOfCipher = s2n(cipher)
bigPrime = 356591097085378373041406631775396675403608993465904761745667548546613469964055945893375233
output, _, _ = xgcd(numOfCipher, bigPrime)
output = output % bigPrime
# output = 233238587670647787805028809001128036933176275182381815462045390514627843647184629262585311
from AITMCLAB.libnum import n2s, s2n, xgcd
bigPrime = 356591097085378373041406631775396675403608993465904761745667548546613469964055945893375233
output = 268287563061576100897937311713001449077245433065661668430027784938038192146644112389472865
key, _, _ = xgcd(24249125136394343, 16156191447296617)
key = key % 16156191447296617 # 取正的余数
# key为24249125136394343的逆元
# (ppx, ppy, gcd) = (-5984828584066420, 8982739386836133, 1)
# key = 10171362863230197
def decode(cpr):
msg = ""
for c in cpr:
if 'a' <= c <= 'z':
now_msg = c - ord('a')
msg += chr(((now_msg - key) % 26) + ord('a'))
else:
msg += chr(c)
return msg
a x + b y = 1 ax+by=1 ax+by=1
加密时使用numOfCipher(a)和bigPrime(b)得到output(x):
n u m O f C i p h e r ∗ o u t p u t + b i g P r i m e ∗ y = 1 numOfCipher~*~output~+~bigPrime~*~y=1 numOfCipher ∗ output + bigPrime ∗ y=1
反之,解密时使用output(a)和bigPrime(b)得到numOfCipher:
o u t p u t ∗ n u m O f C i p h e r + b i g P r i m e ∗ y = 1 output~*~numOfCipher~+~bigPrime~*~y=1 output ∗ numOfCipher + bigPrime ∗ y=1
noc, _, _ = xgcd(output, bigPrime)
noc = noc % bigPrime
cipher = n2s(noc)
cipher = cipher.decode("utf-8")
message = decode(cipher)