中国剩余定理
问题形式
方程组如下(以三个模数为例):
1 | x ≡ a1 (mod n1) |
其中 n1, n2, n3 两两互质,N = n1 * n2 * n3,则在 [0, N-1] 内存在唯一解
物不知数
一个整数,除以 3 余 2,除以 5 余 3,除以 7 余 2,求该数
模数:3, 5, 7,两两互质,N = 3 * 5 * 7 = 105
1. 构造基数框架
对每个模数 ni,我们需找一个数 Mi 满足:
1 | Mi ≡ 1 (mod ni) |
构造方法:令 Ni = N / ni,求出 Ni 模 ni 的逆元 yi,使得 (Ni * yi) ≡ 1 (mod ni),则 Mi = Ni * yi
2. 逐项计算
① n1 = 3,N1 = 105 / 3 = 35
求 35 mod 3 的逆元:35 ≡ 2 (mod 3)
在模 3 的世界里,35 和 2 是等价的
因此,”求 35 模 3 的逆元” 就变成了 “求 2 模 3 的逆元”
2 * 2 = 4 ≡ 1 (mod 3),逆元 y1 = 2
基数:M1 = 35 * 2 = 70
② n2 = 5,N2 = 105 / 5 = 21
21 ≡ 1 (mod 5),逆元 y2 = 1
基数:M2 = 21 * 1 = 21
③ n3 = 7,N3 = 105 / 7 = 15
15 ≡ 1 (mod 7),逆元 y3 = 1
基础:M3 = 15 * 1 = 15
3. 合成解
1 | x = a1*M1 + a2*M2 + a3*M3 |
模 105 得到最小正整数解:
1 | x = 233 mod 105 = 23 |
实战案例
smallModulus(CRT)
1 | module = getPrime(64) |
当用户选择 1 时,服务器会:
随机生成一个 64 位(bit)的素数
p_i计算
r_i = m (mod p_i)将
p_i和r_i以十六进制的形式返回给用户允许无限次循环查询
假设我们查询了 k 次,获得了 k 个不同的 64 位素数 p1, p2, ..., pk 以及对应的余数 r1, r2, ..., rk
我们可以写出如下的模同余方程组:
1 | m ≡ r1 (mod p1) |
由于 pi 全都是不同的素数,因此它们之间必然两两互素(gcd(pi, pj) = 1)
根据中国剩余定理,上述方程组在模 M 的意义下有唯一解,其中

这意味着,只要 M > m,我们通过 CRT 恢复出来的唯一解 x (mod M) 就一定等于原本的明文 m
已知 m < 2^512。每个素数 p_i 是 64 位的,即 p_i ≈ 2^64
我们希望 M = ∏_{i=1}^{k} p_i > 2^512
根据对数的基本性质
1 | log2(A * B) = log2(A) + log2(B) |
应用到 M 上则有

这是因为题目说每个 pi 都是 64 位素数,也就是 2^64
1 | log2(M) = log2(p1) + log2(p2) + …… + log2(pk) |
1 | 64k ≥ 512 => k ≥ 8 |
因此,我们只需要进行 8 次查询,收集 8 组模数和余数,就能完美恢复出 Flag
1 | from pwn import * |