二次剩余与 Tonelli-Shanks 算法详解
二次剩余(Quadratic Residue)是 CTF 密码学里的高频考点。RSA 中解密需要求模 n 的平方根,ECDSA 签名验证涉及二次剩余判定, even 简单的”猜数”题都可能藏着 Legendre 符号的套路。
这篇文章从定义出发,讲清楚什么是二次剩余、怎么判定、怎么求平方根,最后落地到 CTF 中的常见应用。
1. 什么是二次剩余
给定奇质数 p 和整数 a,如果存在 x 使得:
1 | x² ≡ a (mod p) |
则称 a 是模 p 的二次剩余(Quadratic Residue, QR),否则称为二次非剩余(Quadratic Non-Residue, QNR)。
举个例子,p=7:
- 1²=1, 2²=4, 3²=2, 4²=2, 5²=4, 6²=1
- 所以模 7 的二次剩余是 {1, 2, 4},非剩余是 {3, 5, 6}
注意 x 和 -x 给出同一个平方值,所以模 p 有 (p-1)/2 个二次剩余和 (p-1)/2 个二次非剩余。
2. Legendre 符号
定义 Legendre 符号:
1 | (a|p) = 1 如果 a 是模 p 的二次剩余且 a ≠ 0 |
Euler 判别法给出了计算方法:
1 | (a|p) ≡ a^((p-1)/2) (mod p) |
1 | def legendre(a, p): |
3. 高斯互反律
二次互反律是数论中最优美的定理之一:
1 | (p|q) * (q|p) = (-1)^((p-1)/2 * (q-1)/2) |
换句话说:
- 如果 p 或 q ≡ 1 (mod 4),则 (p|q) = (q|p)
- 如果 p 和 q 都 ≡ 3 (mod 4),则 (p|q) = -(q|p)
辅助律:
- (2|p) = 1 当 p ≡ ±1 (mod 8)
- (2|p) = -1 当 p ≡ ±3 (mod 8)
4. Tonelli-Shanks 算法:求模平方根
知道 a 是二次剩余后,怎么求 x 使得 x² ≡ a (mod p)?这就是 Tonelli-Shanks 算法。
4.1 特殊情况:p ≡ 3 (mod 4)
最简单的情况。直接公式:
1 | x ≡ a^((p+1)/4) (mod p) |
1 | def sqrt_mod_congruent_3(a, p): |
4.2 一般情况:Tonelli-Shanks
对于任意奇质数 p,算法步骤:
- 把 p-1 写成 Q * 2^S
- 找一个二次非剩余 z
- 初始化 M=S, c=z^(2^Q), t=a^Q, R=a^((Q+1)/2)
- 循环:
- 如果 t=0,返回 0
- 如果 t=1,返回 R
- 找最小的 i (0 < i < M) 使得 t^(2^i) = 1
- 设 b = c^(2^(M-i-1))
- 更新 M=i, c=b², t=tb², R=Rb
1 | def tonelli_shanks(n, p): |
5. CTF 实战:RSA 解密
RSA 中,如果知道私钥 d,解密就是 m = c^d mod n。但如果题目给了 e=3 且 m 很小,m³ < n,就可以直接开三次方根。类似地,e=2 时就是开平方根。
1 | # RSA 低加密指数攻击,e=3 |
6. CTF 实战:二次剩余编码
有一种隐写术叫”二次剩余编码”:把信息嵌入到模 p 的二次剩余/非剩余序列中。解密时只需要对每个块算 Legendre 符号,1 表示 QR,0 表示 QNR。
1 | def decode_quadratic_residue(data, p): |
7. CTF 实战:Tonelli-Shanks 求 RSA 明文
在 RSA 共模攻击、wiener 攻击等场景中,有时需要对模合数 n 求平方根。如果 n = p*q 且知道 p 和 q,可以分别在 mod p 和 mod q 下求平方根,然后用 CRT 合并。
1 | def sqrt_mod_n(a, p, q): |
8. 雅可比符号
当模数不是质数时,用雅可比符号推广 Legendre 符号。雅可比符号 (a|n) 定义为 n 的所有质因子的 Legendre 符号乘积。
1 | def jacobi(a, n): |
雅可比符号可以高效计算,但它不告诉你 a 是否是模 n 的二次剩余——只有当 n 是质数时才等价于 Legendre 符号。
总结
二次剩余是数论密码学的基础组件。掌握 Legendre 符号判定和 Tonelli-Shanks 求根,能应对 CTF 中大量的密码学题目。关键记住:
- p ≡ 3 (mod 4):直接公式 x = a^((p+1)/4)
- 一般情况:Tonelli-Shanks 算法
- 合数模:分解后 CRT 合并
- CTF 套路:低指数开方、二次剩余隐写、RSA 变体攻击










