Skip to main content0xAdham

Command Palette

Search for a command to run...

BYUCTF: Power Tower

Written by
Avatar of 0xAdham
0xAdham
Published on
--
BYUCTF: Power Tower

Platform: BYUCTF Challenge: Power Tower Category: Crypto Difficulty: Hard

Flag

byuctf{eulers_phi_phunction_is_a_phun_phunction}

Target

<remote-host>:1359. "multi-prime RSA where each factor of n is at most 2^16. Prove you know a fast algorithm to invert the power tower!"

  • Server prints n, c, e, then you must send m within 1 second.
  • n ≈ 392 bits = product of 25 distinct ≤16-bit primes.
  • e is printed as a ^-joined list, e.g. e = 79^31^23^34^...^47 (25 terms), a right-associative power tower 79^(31^(23^(...))), an astronomically large exponent.

The provided chall_modified.py sets NUM_EXPS=1 (single small exponent), a simplification to explain the encryption. The real server uses a 25-high tower, which is the actual challenge.

Two sub-problems

  1. Factor n. Trivial: every prime ≤ 2^16, so trial-divide by the ~6500 primes below 65536. A 392-bit n factors in milliseconds. Then φ(n) = ∏(pᵢ − 1).
  2. Invert the tower. Decryption needs d = E⁻¹ mod φ(n), but E (the tower) is far too large to materialise. The fix: you only need E mod φ(n), and E⁻¹ mod φ = (E mod φ)⁻¹ mod φ.

The key idea: iterated modular tetration

Compute E mod φ without ever building E, via Euler's theorem recursively:

a^X mod m = a^( (X mod φ(m)) + φ(m) ) mod m, valid when X ≥ log2(m) (the +φ(m) term is what makes it correct even when gcd(a,m) ≠ 1, the "phun" part).

Apply it down the tower: to get a₀^(rest) mod m, recurse to get rest mod φ(m), lift by φ(m), then one pow. Why it terminates cheaply: φ(n) = ∏(pᵢ−1) with every pᵢ−1 ≤ 2^16, so φ(n) is 2^16-smooth. And φ of a 2^16-smooth number stays 2^16-smooth (each prime power q^a contributes q^{a-1}(q−1), and q−1 < 2^16). So every modulus in the whole recursion factors by the same small trial division. Depth ≤ 25, all fast.

The +φ(m) lift is only valid when the sub-exponent is truly ≥ log2(m). The very top of a tower is a small number (e.g. 47), so I gate the lift with a capped tower evaluation (tower_capped) that returns the exact value if < 2^800, else a sentinel, giving an exact ≥ φ(m) comparison at every level.

Solution

Pitfalls

  • Don't compute the tower. The naïve E = a**(b**(c**...)) hangs forever building a number with billions of digits (my first attempt did exactly this). You never need E, only E mod φ.
  • gcd(a, m) ≠ 1 levels. Plain a^(X mod φ(m)) is wrong when the base shares a factor with the modulus; the + φ(m) lift fixes it, but only when the sub-exponent really is ≥ log2(m), hence the capped check (the topmost term is small).
  • Verify before sending (pow(m, Emod, n) == c) so you don't waste the 1-second window on a wrong association/parse. Right-associativity was correct here on the first try.
  • φ(n) for squarefree n is ∏(pᵢ−1); pᵢ−1 divides it, so E·d ≡ 1 mod φ≡ 1 mod (pᵢ−1) for every prime → decryption is valid across all 25 factors.

Takeaways

  • "Power tower" / tetration mod is Euler's theorem applied recursively; the whole trick is that the modulus chain φ(φ(...φ(n))) stays smooth here, so each level factors trivially.
  • Smooth/small-prime multi-prime RSA has no security. Factoring is just bounded trial division. The difficulty was entirely the exponent representation, not the modulus.
  • General reusable primitive: tower_mod(arr, m) for evaluating any power tower modulo m.

0xAdham

Edit on GitHub
Last updated: --