$ Crypto: Insane Curves

BITSCTF 2026 By TaklaMan
Flag: BITSCTF{7h15_15_w4y_2_63nu5_6n6}

Challenge

  • Title: Insane Curves
  • Category: Crypto
  • Given files: description.txt, val.txt
  • Flag format: BITSCTF{...}

Given Data

val.txt provides:

  • Prime field modulus p
  • Degree-6 hyperelliptic polynomial coefficients f_coeffs
  • Jacobian points in Mumford form: G = (G_u, G_v), Q = (Q_u, Q_v)
  • enc_flag (32-byte hex string)

Key Weakness

The intended hardness is a DLP on a genus-2 Jacobian: Q = dG.

But the base point sits in a very weak smooth-order subgroup:

  • ((p+1) * G) = 0
  • Hence ord(G) | (p+1)
  • And p+1 is fully smooth:
2^23 * 3^14 * 5^8 * 7^4 * 11^10 * 13^10 * 17^9 * 19^6 * 23^5 * 29 * 31^4

This makes Pohlig-Hellman practical and recovers d.

Discrete Log Recovery

Using Pohlig-Hellman on each prime-power factor, CRT gives:

d = 91527621348541142496688581834442276703691715094599257862319082414424378704170

Verification:

d * G == Q   # True

Encryption Mistake

The ciphertext is not AES-based. It is XOR with a SHA-256 digest of the decimal secret:

keystream = sha256(str(d).encode()).digest()
flag = bytes.fromhex(enc_flag) XOR keystream

Recovered plaintext:

BITSCTF{7h15_15_w4y_2_63nu5_6n6}

Minimal Repro Script

from hashlib import sha256

enc = bytes.fromhex("f6ca1f88bdb8e8dda17861b91704523f914564888c7138c24a3ab98902c10de5")
d = 91527621348541142496688581834442276703691715094599257862319082414424378704170

ks = sha256(str(d).encode()).digest()
flag = bytes(a ^ b for a, b in zip(enc, ks))
print(flag.decode())