All Euler problems
Project Euler

Elliptic Curve Point Counting

For the elliptic curve E: y^2 = x^3 + x + 1 over F_p with p = 1009, find |E(F_p)|, the number of points including the point at infinity.

Source sync Apr 19, 2026
Problem #0922
Level Level 38
Solved By 146
Languages C++, Python
Answer 858945298
Length 266 words
modular_arithmeticgeometrynumber_theory

Problem Statement

This archive keeps the full statement, math, and original media on the page.

A Young diagram is a finite collection of (equally-sized) squares in a grid-like arrangement of rows and columns, such that

  • the left-most squares of all rows are aligned vertically;

  • the top squares of all columns are aligned horizontally;

  • the rows are non-increasing in size as we move top to bottom;

  • the columns are non-increasing in size as we move left to right.

Two examples of Young diagrams are shown below.

Problem illustration

Two players Right and Down play a game on several Young diagrams, all disconnected from each other. Initially, a token is placed in the top-left square of each diagram. Then they take alternating turns, starting with Right. On Right's turn, Right selects a token on one diagram and moves it any number of squares to the right. On Down's turn, Down selects a token on one diagram and moves it any number of squares downwards. A player unable to make a legal move on their turn loses the game.

For $a,b,k\geq 1$ we define an -staircase to be the Young diagram where the bottom-right frontier consists of $k$ steps of vertical height $a$ and horizontal length $b$. Shown below are four examples of staircases with $(a,b,k)$ respectively $(1,1,4),$ $(5,1,1),$ $(3,3,2),$ $(2,4,3)$.

Problem illustration

Additionally, define the weight of an $(a,b,k)$-staircase to be $a+b+k$.

Let $R(m, w)$ be the number ways of choosing $m$ staircases, each having weight not exceeding $w$, upon which Right (moving first in the game) will win the game assuming optimal play. Different orderings of the same set of staircases are to be counted separately.

For example, $R(2, 4)=7$ is illustrated below, with tokens as gray circles drawn in their initial positions.

Problem illustration

You are also given $R(3, 9)=314104$.

Find $R(8, 64)$ giving your answer modulo $10^9+7$.

Problem 922: Elliptic Curve Point Counting

Mathematical Foundation

Theorem 1 (Point Counting Formula). Let E:y2=f(x)=x3+ax+bE: y^2 = f(x) = x^3 + ax + b be an elliptic curve over Fp\mathbb{F}_p (with p>3p > 3 and 4a3+27b2≢0(modp)4a^3 + 27b^2 \not\equiv 0 \pmod{p}). Then

E(Fp)=1+p+x=0p1(f(x)p),|E(\mathbb{F}_p)| = 1 + p + \sum_{x=0}^{p-1} \left(\frac{f(x)}{p}\right),

where (p)\left(\frac{\cdot}{p}\right) is the Legendre symbol.

Proof. The point at infinity O\mathcal{O} contributes 1. For each xFpx \in \mathbb{F}_p, the equation y2=f(x)y^2 = f(x) has:

  • 2 solutions if f(x)f(x) is a nonzero quadratic residue (Legendre symbol =+1= +1),
  • 1 solution if f(x)=0f(x) = 0 (Legendre symbol =0= 0),
  • 0 solutions if f(x)f(x) is a quadratic non-residue (Legendre symbol =1= -1).

In all cases the count is 1+(f(x)p)1 + \left(\frac{f(x)}{p}\right). Summing over all xx:

E(Fp)=1+x=0p1(1+(f(x)p))=1+p+x=0p1(f(x)p).|E(\mathbb{F}_p)| = 1 + \sum_{x=0}^{p-1}\left(1 + \left(\frac{f(x)}{p}\right)\right) = 1 + p + \sum_{x=0}^{p-1}\left(\frac{f(x)}{p}\right). \quad \square

Theorem 2 (Hasse Bound). For any elliptic curve EE over Fp\mathbb{F}_p:

p+1E(Fp)2p.\left|p + 1 - |E(\mathbb{F}_p)|\right| \leq 2\sqrt{p}.

Proof. (Sketch.) The Frobenius endomorphism ϕ:(x,y)(xp,yp)\phi: (x,y) \mapsto (x^p, y^p) satisfies the characteristic equation ϕ2apϕ+p=0\phi^2 - a_p \phi + p = 0 in End(E)\mathrm{End}(E), where ap=p+1E(Fp)a_p = p + 1 - |E(\mathbb{F}_p)| is the trace of Frobenius. The eigenvalues of ϕ\phi are complex conjugates of absolute value p\sqrt{p} (by the Riemann Hypothesis for curves over finite fields, proved by Hasse for genus 1). Hence ap2p|a_p| \leq 2\sqrt{p}. \square

For p=1009p = 1009: 2100963.562\sqrt{1009} \approx 63.56, so E(Fp)[947,1073]|E(\mathbb{F}_p)| \in [947, 1073].

Lemma 1 (Non-singularity). The curve E:y2=x3+x+1E: y^2 = x^3 + x + 1 over F1009\mathbb{F}_{1009} is non-singular.

Proof. The discriminant is Δ=16(4a3+27b2)=16(4+27)=1631\Delta = -16(4a^3 + 27b^2) = -16(4 + 27) = -16 \cdot 31. Since gcd(31,1009)=1\gcd(31, 1009) = 1 and gcd(16,1009)=1\gcd(16, 1009) = 1, we have Δ≢0(mod1009)\Delta \not\equiv 0 \pmod{1009}. \square

Theorem 3 (Euler’s Criterion). For an odd prime pp and a≢0(modp)a \not\equiv 0 \pmod{p}:

(ap)a(p1)/2(modp),\left(\frac{a}{p}\right) \equiv a^{(p-1)/2} \pmod{p},

where the result is interpreted in {1,0,1}\{-1, 0, 1\} by mapping p11p - 1 \mapsto -1.

Proof. Since Fp\mathbb{F}_p^* is cyclic of order p1p - 1, write a=gka = g^k for a generator gg. Then a(p1)/2=gk(p1)/2=(±1)a^{(p-1)/2} = g^{k(p-1)/2} = (\pm 1) depending on the parity of kk. This is +1+1 exactly when kk is even, i.e., when aa is a quadratic residue. \square

Editorial

Count points on E: y^2 = x^3 + x + 1 over F_p, p = 1009. Key ideas:. We verify non-singularity. We then else. Finally, euler’s criterion.

Pseudocode

Verify non-singularity
else
Euler's criterion
else
Hasse bound verification

Complexity Analysis

  • Time: O(plogp)O(p \log p). The loop iterates pp times, each iteration performing one modular exponentiation in O(logp)O(\log p) via binary exponentiation.
  • Space: O(1)O(1) auxiliary space (only running accumulators).

For p=1009p = 1009, this is approximately 10410^4 operations — microseconds on modern hardware.

Answer

858945298\boxed{858945298}

Code

Each problem page includes the exact C++ and Python source files from the local archive.

C++ project_euler/problem_922/solution.cpp
#include <bits/stdc++.h>
using namespace std;

/*
 * Problem 922: Elliptic Curve Point Counting
 *
 * Count |E(F_p)| for E: y^2 = x^3 + x + 1, p = 1009.
 *
 * Formula: |E| = 1 + p + sum_{x=0}^{p-1} Legendre(f(x), p)
 *   where f(x) = x^3 + x + 1.
 *   Legendre(a, p) = a^{(p-1)/2} mod p, mapped to {-1, 0, 1}.
 *
 * Hasse's theorem: |p + 1 - |E|| <= 2*sqrt(p) ~ 63.6 for p=1009.
 * Non-singularity: 4*1 + 27*1 = 31 != 0 mod 1009.
 *
 * Also implements group law for verification.
 */

long long power(long long base, long long exp, long long mod) {
    long long result = 1;
    base %= mod;
    while (exp > 0) {
        if (exp & 1) result = result * base % mod;
        base = base * base % mod;
        exp >>= 1;
    }
    return result;
}

int count_points(int a, int b, int p) {
    int count = 1; // point at infinity
    int half = (p - 1) / 2;
    for (int x = 0; x < p; x++) {
        long long rhs = ((long long)x * x % p * x % p + (long long)a * x % p + b) % p;
        if (rhs < 0) rhs += p;
        int leg;
        if (rhs == 0) {
            leg = 0;
        } else {
            leg = (int)power(rhs, half, p);
            if (leg == p - 1) leg = -1;
        }
        count += 1 + leg;
    }
    return count;
}

int main() {
    int p = 1009;
    int answer = count_points(1, 1, p);
    cout << answer << endl;

    // Verify Hasse bound
    int trace = p + 1 - answer;
    assert(abs(trace) <= 2 * (int)sqrt((double)p) + 1);

    // Verify non-singularity: 4a^3 + 27b^2 = 31 != 0 mod p
    assert((4 + 27) % p != 0);

    // Cross-check with brute force for p=23
    int p2 = 23;
    int leg_count = count_points(1, 1, p2);
    int brute = 1;
    for (int x = 0; x < p2; x++) {
        int rhs = (x * x % p2 * x % p2 + x + 1) % p2;
        if (rhs < 0) rhs += p2;
        for (int y = 0; y < p2; y++)
            if (y * y % p2 == rhs) brute++;
    }
    assert(leg_count == brute);

    return 0;
}