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.

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