Back

An interactive intro to elliptic curve cryptography

Suppose two people want to communicate privately over the internet. They could encrypt their messages, scrambling them so that only someone with the right secret key can read them. But that raises an immediate problem: how do they agree on that secret key in the first place? They can't whisper it to each other. Every message between them passes through the open internet, where anyone could be listening.

If ideas like Modular Arithmetic, Group (math), or Discrete Logarithm feel new, read the crypto-math post first, then come back here. This article assumes those foundations and builds from geometry to full protocols.

One solution is public-key cryptography, where each person has two linked keys: a private key they keep secret and a public key they can share. Anyone can encrypt to your public key, but only your private key can decrypt. The keys are related, but recovering the private key from the public key is computationally infeasible at practical sizes.

The first widely used public-key systems were built on hard math problems. RSA uses the asymmetry between easy multiplication of large primes and hard factorization. Diffie-Hellman uses a related asymmetry with exponents in modular arithmetic (clock arithmetic where numbers wrap around).

Both systems still work, but they share a drawback of having large keys. A commonly recommended minimum for RSA is 2048 bits (about 617 decimal digits), and 128-bit security equivalence is usually mapped to 3072-bit RSA. As security targets increase, RSA key sizes increase quickly.

What if a different mathematical structure could give us the same guarantees (easy in one direction, effectively impossible in reverse) but with much smaller numbers? That structure exists, and it comes from the geometry of curves.

Drawing the curve

A mathematical equation can define a shape. Take the equation y=x2y = x^2, which says "y equals x squared." To draw it, you pick values of xx, compute yy, and plot each resulting point on a grid. Step through the process below:

Plotting y = x²
xy(-3, 9)-3

Each step picks an xx value, squares it to get yy, and places a dot at that coordinate. As the points accumulate, a curve appears: the parabola. The equation defined the shape all along; we just needed enough points to see it.

Different equations produce different shapes. The equation x2+y2=1x^2 + y^2 = 1 gives a circle (every point at distance 1 from the center). Toggle between these below:

Equations draw shapes
y = x²
xy

An elliptic curve is another equation of this kind:

y2=x3+ax+by^2 = x^3 + ax + b

Click y2=x3x+1 y^2 = x^3 - x + 1 in the demo above to see one. The x3x^3 term makes the right side grow much faster than the left, giving the curve its distinctive looping shape, different from the smooth symmetry of a circle or the open bowl of a parabola.

Despite the name, elliptic curves have nothing to do with ellipses. The name comes from elliptic integrals, which arose historically when computing the arc length of an ellipse. The connection is purely mathematical and not worth worrying about.

The constants aa and bb determine the curve's shape. Adjust the sliders below and watch the curve change. Click anywhere on the curve to place a point:

Elliptic curve explorer
y² = x³ 1.0x + 1.0
xy
Click on the curve to place a point

Click a few different spots. Every point you place has a mirror: if (x,y)(x, y) is on the curve, then (x,y)(x, -y) is too, because squaring a negative number gives the same result as squaring its positive counterpart ((y)2=y2(-y)^2 = y^2). The curve is always symmetric across the x-axis. This symmetry will matter when we define addition.

One constraint on the parameters is important: some values of aa and bb produce a cusp or self-intersection. These are singular curves, and they break the algebra we need. Toggle between the three cases below to see what goes wrong:

Singular vs non-singular curves
y² = x³ − x + 1
xy
Smooth curve with no sharp points or crossings. The algebraic structure works.

At a cusp, the curve comes to a sharp point where the tangent line is undefined. At a self-intersection, two branches of the curve cross, giving two tangent lines at one point. Both situations break the point addition we're about to define, which depends on there being exactly one tangent line at every point. The mathematical condition for avoiding singularities is that the discriminant 4a3+27b204a^3 + 27b^2 \neq 0. Cryptographic curves always satisfy this.

We have a curve. Now what? The idea that turned this into cryptography was to define an arithmetic on the points of the curve: a way to "add" two points together and get a third point, also on the curve.

Adding points on a curve

Here's the geometric construction. Take two points PP and QQ on the curve. Draw a straight line through them. Because the equation is cubic (the x3x^3 term), this line will generally intersect the curve at exactly one more point, call it RR' (special cases like vertical lines or tangencies are handled by the point at infinity and the doubling rule). Now reflect RR' over the x-axis, which means flipping its y-coordinate from positive to negative or vice versa. The reflected point RR is the result. We define P+Q=RP + Q = R.

Move the sliders below to slide PP and QQ along the curve and watch the addition happen:

Point addition on an elliptic curve
R'PQP+Q
P = (-1.50, 1.90)Q = (1.80, 2.50)P+Q = (-0.27, -2.13)

The dashed line goes through PP and QQ. It hits the curve at RR' (the unfilled circle). Reflecting RR' over the x-axis gives us P+QP + Q (the red point).

This "addition" isn't ordinary addition. We're not adding the coordinates together. We're using a geometric recipe (draw a line, find the intersection, reflect) to produce a new point from two existing ones. But mathematicians call it addition because it behaves like addition in the ways that matter.

The operation is associative, so P+(Q+R)=(P+Q)+RP + (Q + R) = (P + Q) + R. It has an identity element, the Point at Infinity OO, which behaves like zero: P+O=PP + O = P. Every point also has an inverse, its reflection across the x-axis, because P+(P)P + (-P) gives the point at infinity. Together, these rules make curve points a Group (math), which is exactly what cryptography needs.

The algebra behind this construction uses the line's slope. For two distinct points P=(x1,y1)P = (x_1, y_1) and Q=(x2,y2)Q = (x_2, y_2), the slope of the line through them is:

m=y2y1x2x1m = \frac{y_2 - y_1}{x_2 - x_1}

And the result point (x3,y3)(x_3, y_3) is:

x3=m2x1x2,y3=m(x1x3)y1x_3 = m^2 - x_1 - x_2, \quad y_3 = m(x_1 - x_3) - y_1

But what happens when PP and QQ are the same point? You can't draw a line through a single point. Instead, you use the tangent line, the line that just touches the curve at PP. Its slope comes from calculus (implicit differentiation of the curve equation):

m=3x12+a2y1m = \frac{3x_1^2 + a}{2y_1}

The rest of the formula is the same. This operation, adding a point to itself, is called Point Doubling, and it's the building block for everything that follows.

Climbing the curve

With point doubling, we can compute 2P=P+P2P = P + P, then 3P=2P+P3P = 2P + P, then 4P4P, and so on. Computing nPnP for an integer nn is Scalar Multiplication.

The naive method takes n1n - 1 additions. A faster method is double-and-add. To compute 100P100P, write 100100 as 64+32+464 + 32 + 4 in binary, compute powers of two by repeated doubling, then add only the terms you need. That is eight group operations instead of 99. In general, this takes about log2(n)\log_2(n) steps.

Step through the computation of nPnP on a small curve:

Scalar multiplication
y² = x³ − 2x + 4,   G = (-1.5, 1.9)
Gxy

Watch the points hop around in what looks like a random pattern. Even on this small curve, there's no visible relationship between nn and the position of nPnP. The points don't march along the curve in any recognizable order. They scatter unpredictably.

That apparent randomness is the foundation of elliptic curve cryptography.

The trapdoor

Going forward is easy: given PP and nn, computing Q=nPQ = nP takes roughly log2(n)\log_2(n) steps using double-and-add. Going backward is hard: given PP and QQ, finding nn such that Q=nPQ = nP has no known shortcut on a well-chosen curve.

This is a one-way function: easy to compute, hard to reverse. Public-key cryptography relies on that asymmetry. For RSA, the asymmetry is multiplication vs factorization. For elliptic curves, it is scalar multiplication vs recovering the scalar.

The problem of recovering nn is called the Elliptic Curve Discrete Logarithm Problem. The name "discrete logarithm" comes from an analogy with regular logarithms: in regular math, if bn=xb^n = x, then n=logb(x)n = \log_b(x). Here, if nP=QnP = Q, we're looking for a kind of "logarithm" in the world of elliptic curve points. "Discrete" means we're working with integers, not continuous numbers.

On a well-chosen curve, the best generic attacks (like Pollard's rho) require roughly O(n)O(\sqrt{n}) operations, no fundamentally better shortcut is known.

Step through a brute-force search to see what "going backward" looks like:

Brute-force ECDLP search
Given G: (-1.5, 1.9)
Given Q = nG: (1.57, 2.17)
Find: n = ?
QG1Gxy
Tried 1 of 12 values. No match yet

On the small curve in this demo, the search finishes quickly because nn is small. In real cryptography, nn is roughly 22562^{256} (a number with 77 digits). Even the best known algorithms would need about 21282^{128} operations. If every computer on Earth worked on the problem, it would take longer than the age of the universe.

From smooth curves to scattered dots

Everything so far used real-number coordinates: smooth curves, infinite precision, irrational slopes. Real cryptography can't work this way. Computers represent real numbers with floating-point arithmetic, which introduces tiny rounding errors. In cryptography, a single wrong bit means the wrong answer. We need exact arithmetic.

The fix is to work over a Finite Field. Instead of all real numbers, we use integers from 00 to p1p - 1, where pp is prime. Arithmetic wraps around at pp, just like a clock wraps at 12.

This is modular arithmetic (written modp\bmod p). For example, if p=7p = 7, then 5+4=92(mod7)5 + 4 = 9 \equiv 2 \pmod{7} because 9 leaves remainder 2 when divided by 7.

The curve equation becomes:

y2x3+ax+b(modp)y^2 \equiv x^3 + ax + b \pmod{p}

Now xx and yy are integers from 00 to p1p - 1. Division is replaced by Modular Inverse, a number that, when multiplied, gives 1 modulo pp. (For example, the inverse of 3 modulo 7 is 5, because 3×5=151(mod7)3 \times 5 = 15 \equiv 1 \pmod{7}.) The point addition formulas stay exactly the same, just computed mod pp.

The visual result is completely different. The smooth curve becomes a scattered cloud of dots:

Elliptic curve over a finite field
Curve: y² ≡ x³ + 1x + 6 (mod 23)
Points: 20

Click any point to see its inverse (the point with the same x-coordinate but negated y-coordinate, mod pp). Despite looking random, these points satisfy the same equation and obey the same addition rules. The algebraic structure is fully preserved even though the geometry is gone. It's this version of the curve (over a finite field with a very large prime) that real cryptographic systems use.

The number of points on the curve is close to pp (more precisely p+1tp + 1 - t for a small value tt, by Hasse's theorem). Cryptographic systems typically use a large prime-order Subgroup of size nn close to pp. For curves using 256-bit primes, this gives roughly 22562^{256} points to work in.

Exchanging secrets on a curve

At this point we have what we need: point addition and a one-way function (scalar multiplication). Now we can build a protocol that lets two people agree on a shared secret over a public channel without sending the secret itself.

This protocol is called ECDH. Alice and Bob agree publicly on a curve and a starting point GG called the Generator Point. If you compute G,2G,3G,G, 2G, 3G, \ldots, the points eventually cycle back to the start.

The number of steps before points cycle is the order of GG, written nn. For cryptographic curves, nn is roughly 22562^{256}, so the cycle is huge. Private keys are random scalars in [1,n1][1, n-1]. (Some curves like X25519 accept 32 random bytes and deterministically clamp bits into a safe scalar.)

  1. Alice picks a random secret integer aa as her private key. She computes aGaG as her public key and sends it to Bob.
  2. Bob picks a random secret integer bb as his private key. He computes bGbG as his public key and sends it to Alice.
  3. Alice takes Bob's public key bGbG and multiplies it by her private key: a(bG)=abGa(bG) = abG.
  4. Bob takes Alice's public key aGaG and multiplies it by his private key: b(aG)=baGb(aG) = baG.

Since scalar multiplication is associative, abG=baGabG = baG. Both sides get the same point, the shared secret. An eavesdropper can see GG, aGaG, and bGbG, but deriving abGabG from those values requires solving the ECDLP.

Adjust the private keys below and watch the shared secret update:

ECDH key exchange
Curve: y² = x³ + 1x + 6 (mod 23)
G: (7, 3)
Order: 29
Alice
Private key: a = 7
Public key: aG = (9, 12)
Computes: a(bG) = (4, 7)
Bob
Private key: b = 13
Public key: bG = (15, 17)
Computes: b(aG) = (4, 7)

Both sides always arrive at the same point. In practice, the shared secret (usually just the x-coordinate of this point) is fed through a key derivation function to produce a symmetric encryption key, which is then used to encrypt the actual conversation.

Signing with curves

Key exchange establishes shared secrets. We also need digital signatures, which prove who sent a message and whether it was modified. That is what you rely on for software updates, TLS certificates, and cryptocurrency transactions.

ECDSA works like this. The signer has a private key dd (a secret integer) and a public key Q=dGQ = dG (a point on the curve, published for anyone to see).

To sign a message:

  1. Hash the message to get a number mm (a hash function, like SHA-256, turns any input into a fixed-size number)
  2. Pick a random secret nonce kk (a one-time random number, never reused)
  3. Compute the point R=kGR = kG on the curve
  4. Set r=Rxmodnr = R_x \bmod n (the x-coordinate of RR, taken modulo the group order nn)
  5. Compute s=k1(m+rd)modns = k^{-1}(m + r \cdot d) \bmod n (using the modular inverse of kk)
  6. If r=0r = 0 or s=0s = 0, a new kk must be generated and the process repeated
  7. The signature is the pair (r,s)(r, s)

To verify the signature against the signer's public key QQ:

  1. Compute u1=ms1modnu_1 = m \cdot s^{-1} \bmod n and u2=rs1modnu_2 = r \cdot s^{-1} \bmod n
  2. Compute the point R=u1G+u2QR' = u_1 G + u_2 Q
  3. If the x-coordinate of RR' modulo nn equals rr, the signature is valid

The math works out so that only someone who knows dd can produce a valid (r,s)(r, s) for a given message, but anyone who knows the public key QQ can verify it. Adjust the parameters below to see signing and verification with small numbers:

ECDSA sign and verify
G: (7, 3)
n (order): 29
Public key Q: (14, 5)
Signing
1. Pick random k = 5
2. R = kG = (1, 12)
3. r = R.x mod n = 1
4. s = k⁻¹(m + r·d) mod n = 16
Signature: (r=1, s=16)
Verification
1. u₁ = m·s⁻¹ mod n = 8
2. u₂ = r·s⁻¹ mod n = 20
3. R' = u₁G + u₂Q = (1, 12)
4. v = R'.x mod n = 1
v == r → VALID

Two critical security requirements: the nonce kk must never be reused across different messages, and kk and its inverse must be protected like the private key itself. If an attacker sees two signatures that used the same kk with different messages, the two equations leak enough information to compute the private key dd directly. In 2010, Sony's PlayStation 3 code signing key was extracted because they used the same nonce for every signature, a catastrophic implementation mistake.

Encrypting with curves

ECDH handles key agreement and ECDSA handles signatures. For public-key encryption to a recipient, we use ECIES.

ECIES is a hybrid encryption scheme that combines elliptic curve cryptography with symmetric encryption:

  1. Alice generates a random ephemeral keypair: a private key rr and public key R=rGR = rG
  2. Alice computes the shared secret: S=rQBS = r \cdot Q_B (where QBQ_B is Bob's public key)
  3. Alice derives a symmetric key from SS (usually from the x-coordinate, often through a key derivation function)
  4. Alice encrypts the message using the symmetric key (with AES or similar)
  5. Alice sends (R,ciphertext)(R, \text{ciphertext}) to Bob (the ephemeral public key and the encrypted message)

Bob decrypts by computing the same shared secret:

  1. Bob receives (R,ciphertext)(R, \text{ciphertext})
  2. Bob computes the shared secret: S=dBRS = d_B \cdot R (where dBd_B is his private key)
  3. Bob derives the same symmetric key from SS
  4. Bob decrypts the ciphertext

The math ensures both arrive at the same shared secret because rQB=r(dBG)=(rdB)G=(dBr)G=dB(rG)=dBRr \cdot Q_B = r \cdot (d_B G) = (r \cdot d_B) G = (d_B \cdot r) G = d_B \cdot (rG) = d_B \cdot R.

The ephemeral key rr is generated fresh for every message, which means the same plaintext encrypted twice produces different ciphertexts. An eavesdropper sees RR and the ciphertext, but computing rr from R=rGR = rG requires solving the ECDLP.

Try the demo below. It uses simplified XOR instead of AES so the flow stays easy to follow:

ECIES hybrid encryption
Curve: y² = x³ + 1x + 6 (mod 23)
G: (7, 3)
Bob's public key Q_B: (11, 9)
Message
Encryption (Alice)
1. Random ephemeral r = 7
2. Ephemeral public R = rG = (9, 12)
3. Shared secret S = r·Q_B = (14, 18)
4. Symmetric key k = S.x = 14
5. Ciphertext = encrypt(msg, k)
Send (R, 46672e4c616c...) to Bob
Decryption (Bob)
1. Receive (R, ciphertext)
2. Shared secret S = d_B·R = (14, 18)
3. Symmetric key k = S.x = 14
4. Plaintext = decrypt(ciphertext, k)
Decrypted: "Hi Bob"

ECIES is used in practice for encrypting messages to a recipient's public key without requiring a prior key exchange. Full ECIES specifications also include a key derivation function (KDF) and a MAC or AEAD scheme for integrity. Ethereum's devp2p/RLPx protocol uses ECIES during the handshake to establish shared session keys; the ongoing transport then uses symmetric encryption. Signal Protocol uses a variant called the X3DH key agreement protocol that builds on similar elliptic curve principles.

Why curves win

The practical advantage of elliptic curve cryptography is key size. For the same security level, ECC keys are much smaller than RSA or finite-field Diffie-Hellman keys:

Security levelECC keyRSA keyDH key
80 bits160 bits1,024 bits1,024 bits
112 bits224 bits2,048 bits2,048 bits
128 bits256 bits3,072 bits3,072 bits
192 bits384 bits7,680 bits7,680 bits
256 bits521 bits15,360 bits15,360 bits

"Security level" means the rough operation count needed to break the system. At 128-bit security, ECC uses 256-bit keys while RSA uses 3072-bit keys. At higher levels the gap gets larger: 256-bit security maps to 521-bit ECC vs 15,360-bit RSA.

Smaller keys reduce compute cost, bandwidth, and storage, and they help on constrained devices like smart cards and IoT hardware. That is why modern protocols such as TLS 1.3, Signal, SSH, and Bitcoin use ECC heavily.

  • TLS 1.3 uses ephemeral (EC)DHE key agreement for forward secrecy (static RSA key transport is gone)
  • Signal Protocol (used in Signal and WhatsApp) uses Curve25519 for key agreement
  • SSH supports ECDSA and Ed25519 keys
  • Bitcoin and Ethereum use secp256k1 for transaction signing

The most widely used curves today are NIST P-256 (standardized by NIST around 2000, included in FIPS 186-2) and Curve25519 (designed by Daniel Bernstein in 2006). X25519, the Diffie-Hellman function on Curve25519, was designed to reduce common implementation mistakes: it accepts 32 bytes of secret material and deterministically clamps bits into a safe scalar.

Elliptic curves give us key exchange and signatures with compact keys. The open question is quantum computing: Shor's algorithm would solve ECDLP efficiently on a sufficiently powerful quantum machine. We do not have that machine today, but the risk is why post-quantum cryptography is advancing quickly, using different constructions such as lattices, codes, and hash-based schemes.