数论基础(六)应用实例¶
章节概述¶
数论不仅在数学理论中占重要地位,在实际应用中也有着广泛的用途。本章将通过具体实例展示数论在密码学、随机数生成、编码理论等领域的应用。
学习目标¶
- 理解 RSA 加密算法的数学原理
- 掌握 RSA 密钥生成、加密和解密的实现
- 了解伪随机数生成器的原理
- 掌握线性同余生成器(LCG)的实现
- 了解数论在算法竞赛中的应用
- 完成综合实战项目
(一)RSA 加密算法¶
RSA 算法概述¶
RSA 是一种非对称加密算法,由 Rivest、Shamir 和 Adleman 在 1977 年提出。它是目前应用最广泛的公钥密码算法之一。
数学原理¶
RSA 的安全性基于大整数分解的困难性:
- 密钥生成:
- 选择两个大质数 p 和 q
- 计算 n = p × q
- 计算 φ(n) = (p-1) × (q-1)
- 选择整数 e,满足 1 < e < φ(n) 且 gcd(e, φ(n)) = 1
- 计算 d = e^(-1) mod φ(n)
-
公钥:(e, n),私钥:(d, n)
-
加密:
- 将消息 m 转换为整数 M(0 ≤ M < n)
-
计算密文 C = M^e mod n
-
解密:
- 计算明文 M = C^d mod n
- 将 M 转换回消息 m
完整实现¶
import random
def generate_prime(bits):
"""
生成指定位数的大质数
参数:
bits: 位数
返回:
int: 大质数
"""
while True:
# 生成随机奇数
p = random.getrandbits(bits)
p |= (1 << (bits - 1)) | 1 # 确保最高位和最低位是 1
# 使用米勒-拉宾测试
if miller_rabin(p, k=40):
return p
def generate_rsa_keypair(bits=1024):
"""
生成 RSA 密钥对
参数:
bits: 模数的位数(通常是 1024 或 2048)
返回:
tuple: ((e, n), (d, n)) - (公钥, 私钥)
"""
# 生成两个大质数
p = generate_prime(bits // 2)
q = generate_prime(bits // 2)
# 确保 p ≠ q
while p == q:
q = generate_prime(bits // 2)
# 计算 n 和 φ(n)
n = p * q
phi = (p - 1) * (q - 1)
# 选择 e(常用值:65537)
e = 65537
while gcd(e, phi) != 1:
e = random.randrange(3, phi, 2)
# 计算 d
d = mod_inverse(e, phi)
# 返回密钥对
public_key = (e, n)
private_key = (d, n)
return public_key, private_key
def rsa_encrypt(message, public_key):
"""
RSA 加密
参数:
message: 明文消息(字符串)
public_key: 公钥 (e, n)
返回:
int: 密文
示例:
>>> pub, priv = generate_rsa_keypair(512)
>>> cipher = rsa_encrypt("Hello", pub)
>>> plain = rsa_decrypt(cipher, priv)
>>> print(plain)
Hello
"""
e, n = public_key
# 将消息转换为整数
m = int.from_bytes(message.encode('utf-8'), 'big')
# 确保消息长度小于 n
if m >= n:
raise ValueError("消息太长")
# 加密
c = mod_pow(m, e, n)
return c
def rsa_decrypt(ciphertext, private_key):
"""
RSA 解密
参数:
ciphertext: 密文(整数)
private_key: 私钥 (d, n)
返回:
str: 明文消息
"""
d, n = private_key
# 解密
m = mod_pow(ciphertext, d, n)
# 将整数转换回消息
try:
message = m.to_bytes((m.bit_length() + 7) // 8, 'big').decode('utf-8')
return message
except:
raise ValueError("解密失败")
# 示例使用
if __name__ == "__main__":
# 生成密钥对
print("生成 RSA 密钥对...")
public_key, private_key = generate_rsa_keypair(512)
print(f"公钥: e={public_key[0]}, n={public_key[1]}")
print(f"私钥: d={private_key[0]}, n={private_key[1]}")
# 加密
message = "Hello, RSA!"
print(f"\n原始消息: {message}")
ciphertext = rsa_encrypt(message, public_key)
print(f"密文: {ciphertext}")
# 解密
decrypted = rsa_decrypt(ciphertext, private_key)
print(f"解密消息: {decrypted}")
RSA 的安全性¶
- 大整数分解:攻击者需要分解 n = p × q
- 模数长度:推荐使用至少 2048 位的模数
- 填充方案:实际应用中需要使用 PKCS#1 等填充方案
RSA 的应用¶
- 数字签名
- 密钥交换
- SSL/TLS 协议
- PGP 加密
(二)伪随机数生成器¶
线性同余生成器(LCG)¶
算法:
参数: - m:模数(通常是 2^k) - a:乘数 - c:增量 - X₀:种子(初始值)
class LinearCongruentialGenerator:
"""
线性同余生成器(LCG)
参数:
seed: 种子值
a: 乘数
c: 增量
m: 模数
"""
def __init__(self, seed, a=1103515245, c=12345, m=2**31):
self.seed = seed
self.a = a
self.c = c
self.m = m
def next(self):
"""
生成下一个随机数
返回:
int: [0, m-1] 范围内的随机整数
"""
self.seed = (self.a * self.seed + self.c) % self.m
return self.seed
def random(self):
"""
生成 [0, 1) 范围内的随机浮点数
返回:
float: [0, 1) 范围内的随机浮点数
"""
return self.next() / self.m
def randint(self, a, b):
"""
生成 [a, b] 范围内的随机整数
参数:
a: 下界
b: 上界
返回:
int: [a, b] 范围内的随机整数
"""
return a + int(self.random() * (b - a + 1))
# 示例使用
if __name__ == "__main__":
lcg = LinearCongruentialGenerator(seed=12345)
print("生成 10 个随机数:")
for i in range(10):
print(f" {lcg.random():.6f}")
print("\n生成 5 个 [1, 100] 范围内的随机整数:")
for i in range(5):
print(f" {lcg.randint(1, 100)}")
常见的 LCG 参数¶
POSIX 标准:
ANSI C 标准:
LCG 的缺点¶
- 周期有限
- 统计特性不够好
- 不适用于密码学
其他伪随机数生成器¶
class MersenneTwister:
"""
梅森旋转算法(MT19937)
Python 的 random 模块使用的算法
"""
def __init__(self, seed):
self.mt = [0] * 624
self.index = 624
self.mt[0] = seed
for i in range(1, 624):
self.mt[i] = (1812433253 * (self.mt[i-1] ^ (self.mt[i-1] >> 30)) + i) & 0xFFFFFFFF
def extract_number(self):
if self.index >= 624:
self.twist()
y = self.mt[self.index]
y ^= (y >> 11)
y ^= ((y << 7) & 0x9D2C5680)
y ^= ((y << 15) & 0xEFC60000)
y ^= (y >> 18)
self.index += 1
return y
def twist(self):
for i in range(624):
x = (self.mt[i] & 0x80000000) | (self.mt[(i + 1) % 624] & 0x7FFFFFFF)
self.mt[i] = self.mt[(i + 397) % 624] ^ (x >> 1)
if x % 2 != 0:
self.mt[i] ^= 0x9908B0DF
self.index = 0
def random(self):
return self.extract_number() / 0xFFFFFFFF
(三)算法竞赛应用¶
应用1:快速幂¶
问题:计算 a^b mod m
已经在第二章详细介绍。
应用2:矩阵快速幂¶
问题:计算斐波那契数列的第 n 项
def matrix_multiply(A, B, mod=None):
"""
矩阵乘法
参数:
A, B: 2D 矩阵
mod: 模数(可选)
返回:
矩阵乘积
"""
n = len(A)
m = len(B[0])
p = len(B)
result = [[0] * m for _ in range(n)]
for i in range(n):
for j in range(m):
for k in range(p):
result[i][j] += A[i][k] * B[k][j]
if mod is not None:
result[i][j] %= mod
return result
def matrix_power(A, power, mod=None):
"""
矩阵快速幂
参数:
A: 方阵
power: 幂次
mod: 模数(可选)
返回:
A^power
"""
n = len(A)
result = [[1 if i == j else 0 for j in range(n)] for i in range(n)]
while power > 0:
if power % 2 == 1:
result = matrix_multiply(result, A, mod)
A = matrix_multiply(A, A, mod)
power //= 2
return result
def fibonacci(n, mod=None):
"""
使用矩阵快速幂计算斐波那契数列的第 n 项
参数:
n: 项数
mod: 模数(可选)
返回:
斐波那契数列的第 n 项
示例:
>>> fibonacci(10)
55
>>> fibonacci(100, 1000000007)
687995182
"""
if n <= 0:
return 0
if n == 1:
return 1
# 转移矩阵
F = [[1, 1], [1, 0]]
# 计算 F^(n-1)
result = matrix_power(F, n - 1, mod)
# 返回 F^(n-1)[0][0]
return result[0][0] if mod is None else result[0][0] % mod
应用3:中国剩余定理¶
问题:求解同余方程组
已经在第三章详细介绍。
应用4:欧拉函数¶
问题:计算与 n 互质的数的个数
已经在第四章详细介绍。
(四)实战项目¶
项目1:简易 RSA 加密系统¶
目标:实现一个完整的 RSA 加密系统,包括密钥生成、加密、解密和文件加密功能。
import os
import pickle
class RSAEncryptionSystem:
"""
简易 RSA 加密系统
"""
def __init__(self, bits=1024):
"""
初始化 RSA 系统
参数:
bits: 密钥位数
"""
self.bits = bits
self.public_key = None
self.private_key = None
def generate_keys(self):
"""生成密钥对"""
self.public_key, self.private_key = generate_rsa_keypair(self.bits)
print("密钥生成成功!")
def encrypt_message(self, message):
"""
加密消息
参数:
message: 明文字符串
返回:
int: 密文
"""
if self.public_key is None:
raise ValueError("请先生成密钥对")
return rsa_encrypt(message, self.public_key)
def decrypt_message(self, ciphertext):
"""
解密消息
参数:
ciphertext: 密文(整数)
返回:
str: 明文
"""
if self.private_key is None:
raise ValueError("请先生成密钥对")
return rsa_decrypt(ciphertext, self.private_key)
def save_keys(self, public_file="public_key.pkl", private_file="private_key.pkl"):
"""
保存密钥对到文件
参数:
public_file: 公钥文件路径
private_file: 私钥文件路径
"""
if self.public_key is None or self.private_key is None:
raise ValueError("请先生成密钥对")
with open(public_file, 'wb') as f:
pickle.dump(self.public_key, f)
with open(private_file, 'wb') as f:
pickle.dump(self.private_key, f)
print(f"密钥已保存到 {public_file} 和 {private_file}")
def load_keys(self, public_file="public_key.pkl", private_file="private_key.pkl"):
"""
从文件加载密钥对
参数:
public_file: 公钥文件路径
private_file: 私钥文件路径
"""
with open(public_file, 'rb') as f:
self.public_key = pickle.load(f)
with open(private_file, 'rb') as f:
self.private_key = pickle.load(f)
print("密钥加载成功!")
def encrypt_file(self, input_file, output_file):
"""
加密文件
参数:
input_file: 输入文件路径
output_file: 输出文件路径
"""
with open(input_file, 'r', encoding='utf-8') as f:
message = f.read()
ciphertext = self.encrypt_message(message)
with open(output_file, 'w', encoding='utf-8') as f:
f.write(str(ciphertext))
print(f"文件加密成功!输出到 {output_file}")
def decrypt_file(self, input_file, output_file):
"""
解密文件
参数:
input_file: 输入文件路径
output_file: 输出文件路径
"""
with open(input_file, 'r', encoding='utf-8') as f:
ciphertext = int(f.read())
message = self.decrypt_message(ciphertext)
with open(output_file, 'w', encoding='utf-8') as f:
f.write(message)
print(f"文件解密成功!输出到 {output_file}")
# 示例使用
if __name__ == "__main__":
# 创建 RSA 系统
rsa = RSAEncryptionSystem(bits=512)
# 生成密钥对
rsa.generate_keys()
# 加密消息
message = "Hello, RSA Encryption System!"
ciphertext = rsa.encrypt_message(message)
print(f"\n加密结果: {ciphertext}")
# 解密消息
decrypted = rsa.decrypt_message(ciphertext)
print(f"解密结果: {decrypted}")
# 保存密钥
rsa.save_keys()
# 加密文件
with open('test.txt', 'w', encoding='utf-8') as f:
f.write("这是一个测试文件。")
rsa.encrypt_file('test.txt', 'test_encrypted.txt')
rsa.decrypt_file('test_encrypted.txt', 'test_decrypted.txt')
项目2:伪随机数生成器比较¶
目标:比较不同伪随机数生成器的性能和统计特性。
import time
import statistics
def test_generator(generator, name, iterations=1000000):
"""
测试伪随机数生成器
参数:
generator: 生成器对象
name: 生成器名称
iterations: 测试次数
返回:
dict: 测试结果
"""
# 生成随机数
start_time = time.time()
numbers = [generator.random() for _ in range(iterations)]
end_time = time.time()
# 统计特性
mean = statistics.mean(numbers)
stdev = statistics.stdev(numbers)
minimum = min(numbers)
maximum = max(numbers)
return {
'name': name,
'time': end_time - start_time,
'mean': mean,
'stdev': stdev,
'min': minimum,
'max': maximum
}
if __name__ == "__main__":
# 测试 LCG
lcg = LinearCongruentialGenerator(seed=12345)
lcg_results = test_generator(lcg, "LCG")
# 测试 MT19937
mt = MersenneTwister(seed=12345)
mt_results = test_generator(mt, "MT19937")
# 打印结果
print("伪随机数生成器比较:")
print(f"\n{lcg_results['name']}:")
print(f" 生成时间: {lcg_results['time']:.4f} 秒")
print(f" 均值: {lcg_results['mean']:.6f}")
print(f" 标准差: {lcg_results['stdev']:.6f}")
print(f" 最小值: {lcg_results['min']:.6f}")
print(f" 最大值: {lcg_results['max']:.6f}")
print(f"\n{mt_results['name']}:")
print(f" 生成时间: {mt_results['time']:.4f} 秒")
print(f" 均值: {mt_results['mean']:.6f}")
print(f" 标准差: {mt_results['stdev']:.6f}")
print(f" 最小值: {mt_results['min']:.6f}")
print(f" 最大值: {mt_results['max']:.6f}")
实战练习¶
练习1:实现简单的密码学协议¶
任务:实现 Diffie-Hellman 密钥交换协议
def diffie_hellman_demo():
"""
Diffie-Hellman 密钥交换演示
"""
# 选择公共参数
p = 23 # 小质数(实际应用中应该使用大质数)
g = 5 # 原根
print(f"公共参数: p = {p}, g = {g}")
# Alice 选择私钥
a = 6
A = mod_pow(g, a, p)
print(f"\nAlice: 私钥 = {a}, 公钥 = {A}")
# Bob 选择私钥
b = 15
B = mod_pow(g, b, p)
print(f"Bob: 私钥 = {b}, 公钥 = {B}")
# 计算共享密钥
alice_shared = mod_pow(B, a, p)
bob_shared = mod_pow(A, b, p)
print(f"\nAlice 计算共享密钥: {alice_shared}")
print(f"Bob 计算共享密钥: {bob_shared}")
# 验证密钥相同
assert alice_shared == bob_shared
print(f"\n✓ 共享密钥一致: {alice_shared}")
# 运行
diffie_hellman_demo()
练习2:数论算法性能比较¶
任务:比较不同质数判断算法的性能
def compare_prime_tests():
"""
比较不同质数判断算法的性能
"""
import time
# 测试数据
numbers = [10**i + 267 for i in range(1, 10)]
print("质数判断算法性能比较:\n")
print(f"{'数字':<20} {'试除法':<15} {'米勒-拉宾':<15}")
print("-" * 50)
for n in numbers:
# 试除法
start = time.time()
result1 = is_prime(n)
time1 = time.time() - start
# 米勒-拉宾
start = time.time()
result2 = miller_rabin(n, k=10)
time2 = time.time() - start
# 验证结果一致
assert result1 == result2
print(f"{n:<20} {time1*1000:.4f}ms {time2*1000:.4f}ms")
# 运行
compare_prime_tests()
章节小结¶
本章介绍了数论的实际应用:
- RSA 加密算法:理解 RSA 的数学原理和完整实现
- 伪随机数生成器:掌握 LCG 和 MT19937 的实现
- 算法竞赛应用:掌握快速幂、矩阵快速幂等算法
- 实战项目:完成 RSA 加密系统和伪随机数生成器比较
数论在实际应用中非常重要,特别是在密码学和计算机安全领域。
下一步¶
继续学习第七章:练习题目,巩固所学知识。
重点提醒: - RSA 的安全性基于大整数分解的困难性 - 伪随机数生成器不应该用于密码学 - 数论算法在算法竞赛中非常重要 - 实际应用中需要考虑安全性和性能的平衡