【应用密码学】实验四 公钥密码1——数学基础
一、实验要求与目的
学习快速模幂运算、扩展欧几里得、中国剩余定理的算法思想以及代码实现。
二、实验内容与步骤记录(只记录关键步骤与结果,可截图,但注意排版与图片大小)
1.快速模幂运算的设计思路
快速模幂运算的核心思想是利用二进制表示和平方乘法来减少乘法运算的次数。具体步骤如下:将指数 b 表示为二进制形式。例如,b=13 的二进制表示为 1101。
通过这种表示,可以将幂运算分解为若干次平方和乘法。
从最低位开始逐位处理指数的二进制表示:如果当前位是 1,将当前的 a 乘到结果中。不管当前位是 0 还是 1,都将 a 平方(即 a=a^2modm),并右移一位(相当于除以 2)。在每一步中,都对结果和中间值取模 m,以避免数值过大导致溢出。使用一个循环来处理指数的每一位。循环条件是 b>0,每次循环都将 b 右移一位,直到 b 为 0。
2.扩展欧几里得算法的设计思路:
扩展欧几里得算法是基于经典的欧几里得算法(辗转相除法)进行扩展的。欧几里得算法用于计算两个整数 a 和 b 的最大公约数(gcd(a,b)),其核心思想是利用递归关系: gcd(a,b)=gcd(b,a mod b) 直到 a mod b=0,此时 b 即为最大公约数。目标是找到整数 x 和 y,使得: ax+by=gcd(a,b) 这实际上是将最大公约数表示为 a 和 b 的线性组合。算法通过递归的方式逐步求解 x 和 y。
假设已知: gcd(b,a mod b)=b⋅x1+(a modb)⋅y1。根据欧几里得算法的递归关系,可以推导出:gcd(a,b)=gcd(b,a mod b)。因此: ax+by=b⋅x1+(a mod b)⋅y1。进一步展开 a mod b=a−b⋅⌊b/a⌋,可以得到: ax+by=b⋅x1+(a−b⋅⌊b/a⌋)⋅y1,整理后得到: x=y1 y=x1−⌊b/a⌋⋅y1。当 a=0 时,递归终止,此时: gcd(0,b)=b 对应的线性组合为: 0⋅x+b⋅y=b 因此,x=0,y=1。
通过递归调用扩展欧几里得算法,逐步求解 x 和 y,直到找到满足 ax+by=gcd(a,b) 的整数解。如果 gcd(a,b)=1,则找到了满足 ax+by=1 的解。结果如下图:
3.中国剩余定理设计思路:
首先计算所有模数(除数)的乘积 M,即 M=∏idivisor[i]。这是中国剩余定理的关键基础,因为最终的解将在这个范围内。
对于每个同余方程 x≡remainder[i] (mod divisor[i]),计算 Mi=M/divisor[i],即 M 除以当前模数的商。然后使用 gmpy2.invert 求 Mi 在模 divisor[i] 下的逆元 k。根据中国剩余定理的构造方法,将每个同余方程的解表示为 remainder[i]×k×Mi,并将所有这些项相加,得到一个可能的解 n。
最终的解 n 可能大于 M,因此通过 nmodM 取最小非负解 nmin。返回 nmin,即满足所有同余方程的最小非负整数解。
三、源代码记录
快速模幂运算
def fast_modular_exponentiation(a, b, m):result = 1 base = a % m while b > 0:if b % 2 == 1: result = (result * base) % mbase = (base * base) % m # 将 base 平方并模 mb //= 2 # 将指数 b 右移一位(相当于除以 2)return resulta = 3
b = 13
m = 17
result = fast_modular_exponentiation(a, b, m)
print(f"{a}^{b} mod {m} = {result}")
扩展欧几里得算法
def extended_gcd(a, b):if a == 0:return (0, 1, b)else:x1, y1, gcd = extended_gcd(b % a, a)x = y1 - (b // a) * x1y = x1return (x, y, gcd)# 用户手动输入 a 和 b
a = int(input("请输入整数a: "))
b = int(input("请输入整数b: "))# 使用函数求解 ax + by = gcd(a, b)
x, y, gcd = extended_gcd(a, b)if gcd == 1:print(f"找到 x = {x}, y = {y} 使得 {a}x + {b}y = 1")
else:print(f"没有整数解,因为 gcd({a}, {b}) = {gcd} 不等于 1")
中国剩余定理
import gmpy2
divisor=[3,5,7]
remainder=[2,3,2]def CRT(divisor, remainder):mul = 1for d in divisor:mul *= d # 计算除数列中所有元素的乘积n = 0for i in range(len(divisor)):k = gmpy2.invert(mul // divisor[i], divisor[i])n += remainder[i] * k * (mul // divisor[i])n_min = n % mulreturn n_min# 调用函数并打印结果
result = CRT(divisor, remainder)
print("The smallest solution is:", result)
四、实验思考
求两个数的最大公因数是否还有其他算法?
答:更相减损术是一种古老的求最大公因数的方法,其核心思想是通过反复相减来逐步减小两个数的大小,直到它们相等,此时的值即为最大公因数。具体操作是:每次用较大的数减去较小的数,然后用得到的差替换原来的较大数,继续进行相减操作,直到两个数相等为止。这种方法简单直观,无需复杂的数学运算,仅通过减法即可实现,特别适合于手工计算或在不支持除法运算的环境中使用。
二进制GCD算法,也称为Stein算法,是一种高效计算最大公因数的方法,它通过位运算和减法操作来逐步简化问题。算法的核心思想是利用二进制的特性,首先判断两个数是否都是偶数,如果是,则同时除以2并记录下除的次数;接着通过减法和位移操作逐步减小两个数的差距,直到它们相等,此时的值乘以之前记录的除2的次数即为最大公因数。这种方法避免了复杂的除法运算,仅使用位移和减法,特别适合在计算机中实现,因为它充分利用了计算机对二进制运算的高效处理能力。
此外还有一些其他的方法,如利用Fibonacci数列的性质、利用同余关系等,但这些方法通常只在特定情况下使用,或者作为理论研究的工具。