This is yet another annual Firebird CTF and I only wrote one cryptography challenge this time, Goldilocks. There were one solve (out of 53 participating teams) during the contest period.

Challenge Summary

If you think discrete log is too easy, try discrete log log. It is easier.


In this challenge, we are given primes $p, q$ such that $p = 2q + 1$ and $p$ is 1024 bits. When connected to the server, $x \in [0, 2^{48})$ is generated and we are given $y$ with

$$y \equiv g^{g^x}\ (\text{mod}\ p),$$

where $g = 2$. The goal is to recover $x$ within one hour.


The baby-step-giant-step algorithm

📝 Note. For simplicity, we assume that $\sqrt{N}$ is an integer.

To start with, we want to tackle a simpler problem: the discrete logarithm problem. That is, if we are given $y$ such that $y \equiv g^x \ (\text{mod}\ p)$, our goal is to find $x$. Assuming that $x \in [0, N)$, we can easily find $x$ by using the BSGS algorithm. To do so, we can compute the two sets $L$ and $R$ given by

$$L = \{g^i \ \text{mod}\ p \ |\ i \in [0, \sqrt{N})\}, \quad R = \{y \cdot g^{-j \cdot \sqrt{N}} \ \text{mod}\ p \ |\ j \in [0, \sqrt{N})\}.$$

Coincidentally there will be $l :\equiv g^i \ \in L$ and $r :\equiv y \cdot g^{-j \cdot \sqrt{N}} \in R$ such that $l = r$. Thus,

$$l = r \Longrightarrow g^i \equiv y \cdot g^{-j \cdot \sqrt{N}} \Longrightarrow y \equiv g^{i + j \cdot \sqrt{N}} \ (\text{mod}\ p).$$

Therefore we are able to find the required $x = i + j \cdot \sqrt{N}$ with $\mathcal{O}(\sqrt{N})$ time.

How about discrete-log-log?

The setting is actually pretty similar. We can write $x = i + j \sqrt{N}$, then we have

$$y \equiv g^{g^x} \equiv g^{g^{i + j \sqrt{N}}} \equiv g^{g^i \cdot g^{j \sqrt{N}}}\ (\text{mod}\ p).$$

If we take the $g^i$-th root on both sides, we have

$$y^{g^{-i}} \equiv y^{1/g^i} \equiv g^{g^j \sqrt{N}}\ (\text{mod}\ p)$$

Alike the above section, we can compute the two sets $L$ and $R$ by

$$L = \{y^{g^{-i}}\ \text{mod} \ p \ | \ i \in [0, \sqrt{N})\}, \quad R = \{g^{g^j \cdot \sqrt{N}} \ \text{mod}\ p \ | \ j \in [0, \sqrt{N})\}.$$

We can do the same to find the required $x = i + j \sqrt{N}$.

Some notes on speeding up the process

Naively, we would use the below code to solve the challenge:

# Find x such that y = g^(g^x) mod p.
def dlog(p, g, y):
    q = (p-1) // 2

    lhs = {}
    for i in range(2**24):
        l = pow(y, pow(g, -i, q), p)
        lhs[l] = i

    for j in range(2**24):
        r = pow(g, pow(g, j * 2**24, q), p)
        if lhs.get(r) is None: continue
        i = lhs.get(r)
        return i + j * 2**24

Since the exponentiations under large modulus are very slow, we might be unable to get the solution within time limit. There are some optimizations that can be done:

  1. [Precompute $R$] We can see that $R$ is dependent of $g$, $p$ and $q$ only. Since they are given and fixed for all of the connections, we can compute $R$ before connecting.
  2. [Reduce the number of exponentiations] Let $l_i = y^{g^{-i}}\ \text{mod}\ p$. Since $$l_i \equiv y^{g^{-i}} \equiv y^{g^{-(i+1) + 1}} \equiv y^{g^{-i} \cdot g} \equiv (y^{g^{-i}})^g \equiv {l_{i+1}}^g \equiv {l_{i+1}}^2 \ \text{mod}\ p,$$ we can actually compute $l_{2^{24}}$ and obtain $l_{2^{24} - 1}$, $l_{2^{24} - 2}$, …, $l_0$ by repeatedly squaring the previous number. This significantly decreases the running time.

You will be given the flag after successfully finding the $x$: