Follow the Hops and Reassemble the Symbols | Hopscotch | GaianSpace CTF 2026
🌐 中文版:繁體中文
Seventh and final post in the series. Over the previous six posts the LoRa demodulator grew from single-frequency, fixed-parameter all the way to implicit header, different-SF-per-packet, and drift correction. Here the satellite does one last thing: it hops across multiple frequencies (FHSS), and the demodulator has to reassemble the symbols, scattered across different frequencies, back into time order before it can decode.
Rest of the series: Channel Hop、True Color Is a Lie、Isodata Seven、Subsidy Claim、Two Voices、No Name on the Door
What the challenge is about

The stranger has switched GAIAN-723’s downlink into a frequency-hopping mode, changing frequency every few symbols to shake off a recorder stuck on a single frequency. David opens the SDR’s bandwidth to the max and records the whole thing.
Goal: decode the contents of this hopping downlink and pull out the flag. The files given are a wideband .sigmf-data and the ground-station notes.
Flag format: GAIANSPACE{...}
First, spot that it’s hopping
Make a wideband waterfall of the whole segment and you can see at a glance that the signal doesn’t stay on one frequency. It hops regularly between a few frequency slots. That’s FHSS (frequency-hopping spread spectrum):

Measure it: the carrier switches among a fixed set of channels, each dwell is roughly a fixed number of symbols, then it jumps to the next channel.
The LoRa modulation parameters (SF, BW) are the same in every dwell; only the centre frequency changes.
Reassemble the hop sequence
The solution has two layers:
Estimate the hopping plan. Run an FFT over each time window to find the dominant frequency, giving you a time → frequency sequence. The channel set is a fixed handful of values, the dwell time is fixed, and the hop order is periodic (pseudo-random but repeating). Organize it into a hop table:

Follow the hops and stitch the symbols together. For each dwell, bring the signal back to baseband (multiply by
exp(-j2πf·t)to move that channel to 0), decode that segment’s symbols with the same demodulator from the earlier posts, then join all the dwells’ symbols end to end in time order to recover the full symbol stream.
The trap here is the dwell boundary: there’s a short transition at the instant of a hop, so drop half a symbol at each end of a dwell and align each dwell’s symbol phase, so they don’t misalign when joined. After alignment, the whole symbol stream decodes through the standard pipeline (Gray → de-interleave → de-whiten XOR), and the packet ends with a CRC that checks out.
Flag
The decoded downlink carries the flag directly:
1 | GAIANSPACE{h0p_sc0tch_AF44A6} |
Takeaways
- The first step of FHSS is always “estimate the hopping plan.” A wideband waterfall plus a per-window FFT for the dominant frequency lets you plot “time → channel”; hopping is usually a periodic pseudo-random sequence, and once you spot the period the whole table is fixed.
- Hopping just scatters the symbols across frequencies; the decoding core is unchanged. After bringing each dwell back to baseband, it’s still the same LoRa demodulator, which is exactly why the earlier posts spent the effort getting the skeleton solid.
- Watch the dwell boundaries. There’s a transition at the moment of a hop, so leave a little margin at each end and align the phase before joining, or the symbols misalign at the seams.
- By this point, the LoRa demodulator hand-built since True Color Is a Lie can handle everything thrown at it: two transmitters, implicit headers, a different SF per packet, Doppler drift, and frequency hopping. One demodulator, seven challenges. That’s the most satisfying part of this whole series.

