我正在为RSA算法创建所有必要的功能。不幸的是,我似乎无法做出适当的Carmichael功能。
这些是我写的功能:
def gcd(a, b): # Greatest Common Divisor Generator (Euclidean Algorithm)
while b != 0: # While remainder exists
t = b # Initially r[k-1]
b = a % t # Initially r[k] = r[k-2] mod r[k-1] (where r[k-2] is a)
a = t # Predecessor of remainder (b)
return a
def phi(n): # Leonard Euler's Totient Function
y = 0
for k in range(1, n + 1): # Phi(+n) is the number of integers k in the range (1 <= k >= n)...
if gcd(n, k) == 1: # for which gcd(n, k) = 1
y += 1
return y
def carmichael(n): # Robert Daniel Carmichael's Function
y = (phi(n) * 1/2) if (n > 4 and ((n & (n - 1)) == 0)) else phi(n) # phi(n) * 1/2 if 2^x = n, else phi(n) * 1
return y
我正在使用totient函数进行数字生成。根据我的知识,有一个简单的规则,如果数字是2的幂并且它大于4,它的素数的数量应该减半,否则它等于phi(n)。
上面的规则完全适用于我的代码,例如,如果输入值为8,则结果如下:
phi(8) = 4
carmichael(8) = 2
但问题是,Carmichael函数由于某种原因也将其他数字减半,例如如果输入为12,这就是我的函数返回的结果:
phi(12) = 4
carmichael(12) = 4
但这应该是这样的:
phi(12) = 4
carmichael(12) = 2
为什么会这样?也许非素数奇数应该区别对待?有什么东西需要添加到我的功能中吗?
谢谢!
答案 0 :(得分:0)
首先,我们创建gcd
函数以计算2个数字的最大公约数,稍后在lambda函数中将需要它。
def gcd(a,b):
while (a>0):
b=b%a
(a,b)=(b,a)
return b
然后我们看一下carmichael函数的工作原理。
让 n 为正整数。然后将λ(n)定义为最小的正整数 k ,这样
a ^k≡1( mod n)
对于所有 a ,例如gcd(a,n)=1
。
请注意,我们正在寻找k
,一旦有了n,就确定a
的值。
现在我们以默认条件初始化函数
n=int(n)
k=2
a=1
alist=[]
要查找所有值,我们使用gcd(a,n)=1
测试 a 和 n 是否具有最大的公因数为1,这意味着它们是互质的。 br />
如果没有,请使用a ++
如果为gcd(a,n)==1
,我们将此值存储到 a 的列表中,然后测试下一个a,直到测试所有a<=n
while not ((gcd(a,n))==1):
a=a+1
while ((gcd(a,n))==1) & (a<=n) :
alist.append(a)
a=a+1
while not ((gcd(a,n))==1):
a=a+1
好吧,我们现在在列表列表中都有一个,请回顾一下定义
最小正整数k使得
a^k≡1(mod n)
首先,我们计算a的数量,即alist的长度
timer=len(alist)
那我们用
if (a**k)%n==1:
测试此k是否使清单中的所有值都为a^k≡1(mod n)
。我们构造一个循环
for a in alist:
if (a**k)%n==1:
timer=timer-1
if timer <0:
break
pass
else:
timer=len(alist)
k=k+1
要测试2中的所有k个数,如果不满足要求,我们执行k=k+1
现在我们具有以下全部功能
def carmichael(n):
n=int(n)
k=2
a=1
alist=[]
while not ((gcd(a,n))==1):
a=a+1
while ((gcd(a,n))==1) & (a<=n) :
alist.append(a)
a=a+1
while not ((gcd(a,n))==1):
a=a+1
timer=len(alist)
while timer>=0:
for a in alist:
if (a**k)%n==1:
timer=timer-1
if timer <0:
break
pass
else:
timer=len(alist)
k=k+1
return k