Discrete Log Signature Forgery via Smooth-Order Modulus Lifting (n=p², Pohlig-Hellman + Hensel Lift)
- •
What it is
- •
A substantially more powerful generalization of the basic DSKS attack, for verifiers that reject a self-supplied modulus if it's prime (blocking the simplest trick) but don't check how it's composite. Choosing for a specially-constructed smooth prime (one where factors entirely into small primes) — large enough that never wraps for the exponents involved — turns "find an making for an arbitrary target digest " into a two-stage, efficiently solvable problem: first, Pohlig-Hellman efficiently solves the discrete log (fast specifically because is smooth); second, a Hensel-lifting step extends that solution from mod up to mod , finding the correction term in that makes the full congruence hold exactly. Because a fresh, valid can be derived this way for any chosen target digest , the same fixed signature can be "verified" as authentic against arbitrarily many different attacker-chosen messages.
- •
- •
When to apply
- •
A DSKS-style attack is blocked by a naive
isPrime(n)check on the attacker-supplied modulus, but the verifier doesn't validate the structure of a composite modulus beyond that — and, ideally, the attacker needs to forge signatures over more than one message using the same fixed base signature .
- •
- •
Math
- •
Writing any valid exponent as for (since ), and using for (Fermat, lifted): . This "" binomial-vanishing structure is exactly the same mechanism as Discrete Log Reduction via Chosen Composite Modulus n=q² (Paillier's Trick), just used here to lift an existing solution rather than to trivialize a discrete log from scratch.
- •
- •
Worked example
- •
A toy 24-bit smooth prime (with built entirely from tiny prime factors) and a primitive-root base : brute-force solving for a random target (standing in for real Pohlig-Hellman on a larger smooth prime), then applying the Hensel lift formula for and assembling , produced an exponent satisfying exactly.
- •
- •
Python
- •
k = ((pow(S, p-1, p*p) - 1) // p) % p k_inv = pow(k, -1, p) # e0 found via Pohlig-Hellman (feasible because p-1 is smooth) diff = (D * pow(S, -e0, p*p) - 1) % (p*p) y = ((diff // p) * k_inv) % p e = e0 + y * (p - 1) assert pow(S, e, p*p) == D
- •
- •
- •
Cards
- •
Why must p specifically be chosen as a smooth prime for this attack to be efficient?
- •
Pohlig-Hellman's efficiency depends on p-1 factoring into small primes — a smooth p-1 is exactly what makes the discrete log mod p tractable.
- •
- •
What's the role of the Hensel lift step, beyond just solving the discrete log mod p?
- •
It extends a solution valid mod p up to one valid mod p², since φ(p²)=p(p-1) means the true exponent space is p times larger than what solving mod p alone determines.
- •
- •