Firebird CTF 2024: Goldilocks
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.
nc HOST PORT
Attachments: chall.py
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.
Solution⌗
The baby-step-giant-step algorithm⌗
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:
- [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.
- [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$:
firebird{w3l1_th15_i5_4n0th3r_d10g_ch4l1en93}