Williams p+1 以及 Pollard’s p-1 分解算法

Williams p+1分解算法

它是对 RSA 模数 n = p*q 发起攻击的一种方法,核心思想是利用某一个因数(通常是 p)满足“p+1 是 B-平滑数”,也就是说 p+1 只由小素数构成(比如 2 × 3 × 5 × 7 × ...)这种情况,能高效地分解 n

🧠 核心思想解析

这个攻击基于:

  • Lucas 序列:是一种类似 Fibonacci 的递推序列,在特定模下有很强的结构性。

  • p+1 平滑假设:如果 p+1 = k 是 B-平滑的(即它的所有因子都小于某个界限 B),我们可以通过构造特定序列将其“暴力爆破”出来。

下面是代码展示:

from math import isqrt
from gmpy2 import gcd
from Cryptodome.Util.number import long_to_bytes
from itertools import count
from sympy import primerange

# 示例已知参数,待分解的n
n = 151767047787614712083974720416865469041528766980347881592164779139223941980832935534609228636599644744364450753148219193621511377088383418096756216139022880709
# Lucas 序列(Williams p+1 用的)
def mlucas(v, a, n):
    v1, v2 = v, (v ** 2 - 2) % n
    for bit in bin(a)[3:]:
        if bit == "0":
            v1, v2 = (v1 ** 2 - 2) % n, (v1 * v2 - v) % n
        else:
            v1, v2 = (v1 * v2 - v) % n, (v2 ** 2 - 2) % n
    return v1

# 素数生成器
def primegen():
    yield from primerange(2, 10**6)  # 生成到 10^6 的素数,够用了

# 整数对数:ilog(x, b) = 最大整数 l,使得 b^l <= x
def ilog(x, b):
    l = 0
    while x >= b:
        x //= b
        l += 1
    return l

# Williams p+1 分解攻击
def attack(n):
    for v in count(1):  # 不断尝试新的 v
        for p in primegen():
            e = ilog(isqrt(n), p)
            if e == 0:
                break
            for _ in range(e):
                v = mlucas(v, p, n)
            g = gcd(v - 2, n)
            if 1 < g < n:
                return int(g), int(n // g)
            if g == n:
                break

# 开始攻击
p1, q1 = attack(n)
print(f"p = {p1}")
print(f"q = {q1}")

Pollard’s p-1 分解算法

✅ 用在什么时候?

当你怀疑 p-1 很光滑,也就是 p-1 是由很多小素数乘出来的时候。

🧠 一句话原理

如果一个大整数 n = p × q,而且某个因数 pp-1 是平滑数(就是只包含小素数因子的数),那我们可以用指数运算和 GCD 把 pn 里揪出来。

🧪 攻击的关键点:

如果我们设:

M也就是一个由小素数乘出来的数(B 是我们控制的界限),只要 p-1 能整除这个 M,我们就有:

所以:

就是我们要找的因子!

下面是代码展示:

from math import gcd
from sympy import primerange
from math import isqrt

def pollard_p_minus_1(n, B=10**5): # B为素数表的上限,可以根据实际往上调
    a = 2  # 通常选2作为基
    for p in primerange(2, B):
        e = int(isqrt(n).bit_length() / p.bit_length())
        a = pow(a, pow(p, e), n)
    g = gcd(a - 1, n)
    if 1 < g < n:
        return g, n // g
    else:
        return None

# 示例参数n:
n = 198962376391690981640415251545285153602734402721821058212203976095413910572270
result = pollard_p_minus_1(n)
if result:
    p, q = result
    print(f"[+] Success! p = {p}, q = {q}")
else:
    print("[-] Failed. Try increasing B.")

如果没有找到,B的大小可以试试从 10^5(10万)开始,往上调,10^6,10^7,甚至 10^8,最多不要超过 10^9,不然计算会很慢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值