Skip to content

Conversation

@x-64
Copy link
Contributor

@x-64 x-64 commented Dec 16, 2025

It's possible to reconstruct the parameters of the EC to:

a: 121...807
b: 791...437
p_orig: 190...587 (128 bit original)
p_new: 132...673 (512 bit after change #132)

But the p_new breaks the special type (anomalous) of the curve.

E = EllipticCurve(GF(p_orig), [a, b])
E.order() = 190...587 == p_orig

E = EllipticCurve(GF(p_new), [a, b])
E.order() = 132...551 != p_new

Analyzing the original curve shows a generation process by the CM method with discriminant D=163 and an additional scaling of a and b by 84557434003015851013164945005322176013 to hide the process/structure of generation.
The original prime from the challenge was choosen randomly.

p = 190...587
F = GF(p)
# The j-invariant for D=163
j = F(-640320^3)
# The scaling factor
u = 84557434003015851013164945005322176013
# Standard construction based on j = 1728 * 4a^3 / (4a^3 + 27b^2)
k = j / (1728 - j)
a_raw = 3 * k
b_raw = 2 * k
# Apply the scaling factor u
print(a_raw * (F(u)**4))
print(b_raw * (F(u)**6))

121...807
791...437

With this, some checks for e.g. a twisted curve and a choosen p with 256 bit, it's possible to build a similar curve having the same properties as the original one but is capable of carrying the two 256 bit sized parts of the pwn.college flag.

# SAGE GENERATOR FOR 256-BIT ANOMALOUS CURVE
def generate_anomalous_parameters(bits):
    # Using the CM method with discriminant D = 163
    # The condition for an anomalous curve (trace=1) is: 4p - 1 = D * v^2
    # Search for v such that p = (163 * v^2 + 1) // 4 is prime
    D = 163
    print(f"[*] Searching for {bits}-bit prime p for Anomalous Curve (D={D})...")

    while True:
        # v must be roughly half the bits of p
        v = randint(2**(bits//2 - 4), 2**(bits//2 - 3))

        # Ensure 163 * v^2 + 1 is divisible by 4
        if v % 2 == 0: continue

        p = (D * v^2 + 1) // 4

        if p.bit_length() == 256 and is_prime(p):
            break

    print(f"[+] Found Prime p: {p}")

    # For D = 163, the j-invariant is known: j = -640320^3
    # Construct the curve y^2 = x^3 + ax + b from this j-invariant
    F = GF(p)
    j = F(-640320^3)

    # Formula to get a, b from j-invariant
    k = j / (F(1728) - j)
    a = 3 * k
    b = 2 * k

    # The scaling factor from original challenge
    u = 84557434003015851013164945005322176013

    # Apply the scaling factor u
    a = a * (F(u)**4)
    b = b * (F(u)**6)
    E = EllipticCurve(F, [a, b])

    # Verify the order of E is exactly p (anomalous)
    if E.order() == p:
        print("[+] Curve is Anomalous! (|E| == p)")
    else:
        # Hit the twist, just try another v
        print("[-] Hiting the twist, retrying...")
        return generate_anomalous_parameters(bits)

    # Check for Singularity
    # A valid EC must have a non-zero discriminant mod p
    if E.discriminant() % p != 0:
        print("[+] The curve is non-singular")
    else:
        print("[-] The curve is singular")
        return generate_anomalous_parameters(bits)

    # Check for Heegner Discriminant D = 163
    # Check if (4p - 1) is divisible by 163 and if the result is a perfect square (v^2)
    D = 163
    val = 4 * p - 1
    if val % D == 0:
        v_sq = val // D
        is_v_square = is_square(v_sq)
        print("[+] 4p - 1 = 163 * v^2 is square")
        if is_v_square:
            print(f"    v = {sqrt(v_sq)}")
    else:
        print("[-] 4p - 1 is not divisible by 163")
        return generate_anomalous_parameters(bits)

    # Check j-invariant
    # For D=163, the j-invariant should be -640320^3 mod p
    if E.j_invariant() == F(-640320^3):
        print("[+] j-invariant matches for D = 163")
    else:
        print("[-] j-invariant does not match for D = 163")
        return generate_anomalous_parameters(bits)

    print(f"a = {a}")
    print(f"b = {b}")
    print(f"p = {p}")

# Run it
generate_anomalous_parameters(256)

[*] Searching for 256-bit prime p for Anomalous Curve (D = 163)...
[+] Found Prime p: 591...757
[+] Curve is Anomalous! (|E| == p)
[+] The curve is non-singular
[+] 4p - 1 = 163 * v^2 is square
v = 380...873
[+] j-invariant matches D = 163
a = 178...461
b = 429...900
p = 591...757

This closes #145.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the elliptic curve parameters in the "dumber" challenge from a 512-bit prime to a 256-bit prime to properly maintain the anomalous curve property. The original 512-bit parameters broke the special anomalous property (where curve order equals the prime), so new parameters were generated using the CM method with discriminant D=163 to create a properly functioning anomalous curve.

Key changes:

  • Replace EC parameters (a, b, p) with new 256-bit values that preserve the anomalous curve property
  • The new curve maintains j-invariant -640320^3 and has order equal to p

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +6 to +8
a = 17801836189733377785295362029761667987972501213297452798611574944384395030461
b = 42981949191870239792389518377291345948295848297527160008386893923017818487900
p = 59143948222596372861761000728366832120206904374471306879672978099984384207757
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description states "p_orig: 190...587 (128 bit original)" and "p_new: 132...673 (512 bit after change #132)", but these values don't match the actual changes. The old p value (removed line) is a 512-bit number starting with "132915106928..." (matching the description's p_new), and the new p value (added line) is 59143948222596372861761000728366832120206904374471306879672978099984384207757 (256 bits, starting with "591...757" from the generator output). This suggests either: (1) the PR description documents a different change than what was implemented, or (2) the code changes are incorrect. The description's generator output matches the new values, so the description's claim about bit sizes appears to be the error.

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +8
#a,b,p = ?,?,?
a = 17801836189733377785295362029761667987972501213297452798611574944384395030461
b = 42981949191870239792389518377291345948295848297527160008386893923017818487900
p = 59143948222596372861761000728366832120206904374471306879672978099984384207757
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The chosen elliptic curve parameters a, b, and p define an anomalous curve with #E(F_p) = p, which makes the discrete log problem on this curve solvable in polynomial time (e.g., via the Smart–Semaev–Satoh–Araki family of attacks). An attacker seeing p, E.random_element() points, and their scalar multiples (as printed later in this script) can efficiently recover the underlying scalars and thus reconstruct the split flag parts. To avoid this, use a non-anomalous curve whose group order has a large prime factor (or a standard, well-vetted curve), ensuring that #E(F_p) is not equal to p and that no known sub-exponential attacks apply.

Suggested change
#a,b,p = ?,?,?
a = 17801836189733377785295362029761667987972501213297452798611574944384395030461
b = 42981949191870239792389518377291345948295848297527160008386893923017818487900
p = 59143948222596372861761000728366832120206904374471306879672978099984384207757
# Use secure, non-anomalous NIST P-256 curve parameters over F_p
p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff
a = -3
b = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

l3akctf2025 crytpo-50-dumber

2 participants