Introduction

Almost every secure connection you make — a banking app, a chat message, the padlock in your browser — leans on a single idea: an operation that is easy to do but hard to undo. RSA gets there by multiplying two giant primes; multiplying is cheap, factoring the product back is not.

Elliptic-curve cryptography (ECC) reaches the same goal with a different, more efficient trick. Take a gentle curve like y2y^{2} = x3x^{3} + ax + b, pick a starting point G, and define a strange kind of "addition" of points using nothing but a ruler. Adding G to itself k times is fast. But given only the final point, recovering the count k — the elliptic-curve discrete-log problem — appears to be astronomically hard.

The payoff is dramatic: a 256-bit ECC key offers roughly the same security as a 3072-bit RSA key. Smaller keys, faster math, less battery — which is exactly why your phone, your messaging app, and modern websites quietly moved to curves.

Add Points on a Curve

Here is a small curve over a finite field. There is a base point G, and a ruler-and-flip rule for "adding" points: draw the line through two points, find where it meets the curve a third time, and reflect that over the horizontal axis. To add a point to itself, use the tangent line.

<p class="hint">On an elliptic curve you can <b>"add"</b> two points with a ruler:
draw the line through them, find the third place it hits the curve, and flip it
over the x-axis. Press <b>Add G</b> to keep adding the same base point G to itself
and watch the chord-and-tangent rule jump around. Going forward is easy — but given
only the final point, recovering <i>how many times</i> you added is the hard part.</p>
<canvas id="cv" width="360" height="300"></canvas>
<div class="readout" id="readout">P = G</div>
<div class="btns">
  <button id="add" type="button">Add G  (P → P + G)</button>
  <button id="reset" type="button" class="ghost">Reset to G</button>
</div>
<p class="dlp">Secret multiplier so far: <b><span id="k">1</span></b>. A real curve uses a 256-bit secret — reversing it is the
\ <b>elliptic-curve discrete-log problem</b>, believed to need astronomically many steps.</p>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .7rem; line-height: 1.45; }
canvas { background: #f7f9fb; border: 1px solid #cdd9e3; border-radius: 8px; display: block; max-width: 100%; }
.readout { font: 600 15px ui-monospace, monospace; color: #1d3557; margin: .6rem 0; min-height: 1.3em; }
.btns { display: flex; gap: .5rem; flex-wrap: wrap; }
button { font: 600 14px system-ui, sans-serif; padding: .45rem .9rem; border: 1px solid #1d3557;
         background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
.dlp { font-size: .88rem; color: #555; line-height: 1.45; margin: .7rem 0 0; }
.dlp b span { color: #c92f3c; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// We work over a small finite field GF(17) so the arithmetic is exact, but we
// DRAW the points on the smooth real curve y^2 = x^3 + 2x + 2 for intuition.
// Group law (chord-and-tangent):
//   - line through P and Q meets the curve in a third point; reflect it over
//   - to add P to itself, use the tangent line (slope from calculus).
// Forward (k -> kG) is a handful of additions. Backward (kG -> k) is the
// elliptic-curve discrete-log problem, the basis of ECC (Koblitz & Miller, 1985).
const P = 17, A = 2, B = 2;          // curve over GF(17)
const G = { x: 5, y: 1 };            // base point, generates 19 points
const mod = (n, m) => ((n % m) + m) % m;
function inv(a, p){ a = mod(a, p); for (let i = 1; i < p; i++) if (mod(a*i, p) === 1) return i; return 0; }
function add(p1, p2){
  if (!p1) return p2; if (!p2) return p1;
  if (p1.x === p2.x && mod(p1.y + p2.y, P) === 0) return null;   // P + (-P) = O
  let s;
  if (p1.x === p2.x && p1.y === p2.y) s = mod((3*p1.x*p1.x + A) * inv(2*p1.y, P), P);
  else s = mod((p2.y - p1.y) * inv(p2.x - p1.x, P), P);
  const x = mod(s*s - p1.x - p2.x, P);
  const y = mod(s*(p1.x - x) - p1.y, P);
  return { x, y };
}

let cur = { ...G }, k = 1, prev = null;
const cv = document.getElementById('cv'), ctx = cv.getContext('2d');

// Map field coords (0..16) onto the canvas with a margin.
const M = 28, W = cv.width - 2*M, H = cv.height - 2*M;
const sx = v => M + (v / 16) * W;
const sy = v => cv.height - M - (v / 16) * H;

function drawCurve(){
  ctx.clearRect(0, 0, cv.width, cv.height);
  // axes
  ctx.strokeStyle = '#d3dce4'; ctx.lineWidth = 1;
  ctx.beginPath(); ctx.moveTo(M, sy(8)); ctx.lineTo(cv.width - M, sy(8)); ctx.stroke();
  // every point of the group, faint
  const all = [];
  let t = { ...G };
  for (let i = 0; i < 25 && t; i++){ all.push(t); t = add(t, G); }
  ctx.fillStyle = '#9fb2c8';
  for (const p of all){ ctx.beginPath(); ctx.arc(sx(p.x), sy(p.y), 3, 0, 7); ctx.fill(); }
  // base point G
  ctx.fillStyle = '#1d3557';
  ctx.beginPath(); ctx.arc(sx(G.x), sy(G.y), 5, 0, 7); ctx.fill();
  ctx.fillText('G', sx(G.x) + 7, sy(G.y) - 6);
  // current point kG
  ctx.fillStyle = '#e63946';
  ctx.beginPath(); ctx.arc(sx(cur.x), sy(cur.y), 6, 0, 7); ctx.fill();
  ctx.font = '600 12px ui-monospace, monospace'; ctx.fillStyle = '#c92f3c';
  ctx.fillText(k + 'G', sx(cur.x) + 8, sy(cur.y) - 6);
  // connecting hop from previous point (the "ruler" idea)
  if (prev){
    ctx.strokeStyle = '#e63946'; ctx.setLineDash([4, 3]); ctx.lineWidth = 1.5;
    ctx.beginPath(); ctx.moveTo(sx(prev.x), sy(prev.y)); ctx.lineTo(sx(cur.x), sy(cur.y)); ctx.stroke();
    ctx.setLineDash([]);
  }
}
function readout(){
  document.getElementById('readout').textContent =
    cur ? (fmt('%k%G = (%x%, %y%)   over GF(17)', { k: k, x: cur.x, y: cur.y })) : (fmt('%k%G = O (point at infinity)', { k: k }));
  document.getElementById('k').textContent = k;
}
function step(){
  prev = cur;
  cur = add(cur, G); k++;
  if (!cur){ // wrapped past the whole group — restart the cycle
    cur = { ...G }; k = 1; prev = null;
  }
  drawCurve(); readout();
  console.log(k + 'G = ' + (cur ? '(' + cur.x + ',' + cur.y + ')' : 'O'));
}
function reset(){ cur = { ...G }; k = 1; prev = null; drawCurve(); readout(); }
document.getElementById('add').addEventListener('click', step);
document.getElementById('reset').addEventListener('click', reset);
ctx.font = '600 12px ui-monospace, monospace';
reset();
Result
Console

Press Add G to compute G, 2G, 3G, … one hop at a time. Going forward is effortless — a short chain of additions lands you on kG. Now imagine I hand you only the red point and ask: how many times did I add G? With a tiny curve you could count. With a real 256-bit curve there are more points than atoms in the visible universe, and counting is hopeless. That asymmetry — easy forward, brutal backward — is the whole game, just like the discrete logarithm.

The Real Complexity

How hard is it really to break a curve? The security rests entirely on the elliptic-curve discrete-log problem (ECDLP): given G and kG, recover k.

  • Forward is cheap. Computing kG takes only about log⁡2(∗k∗)\log_{2}(*k*) point additions via repeated doubling — a few hundred operations even for a 256-bit k.
  • Backward looks brutal. The best known general attacks (Pollard's rho, baby-step/giant-step) run in time around the square root of the group size — about 21282^{128} steps for a 256-bit curve. That is why ECC keys can be so small relative to RSA.
  • It is not proven hard. ECDLP is believed intractable, but there is no proof. Nobody has shown it lies outside P, and a clever classical algorithm could in principle exist — the same open uncertainty that surrounds P vs NP.
  • Quantum changes everything. Shor's algorithm (1994) solves ECDLP in polynomial time on a large quantum computer, just as it cracks factoring. Curves are safe against today's machines, not tomorrow's.

Elliptic curves in cryptography were proposed independently by Neal Koblitz and Victor Miller in 1985. Four decades on, no efficient classical break exists — but "no one has broken it yet" is a very different statement from "it is provably hard."

Where It Matters

You almost certainly used an elliptic curve in the last few minutes:

  • The web (TLS/HTTPS): modern key exchange uses Curve25519 (X25519), so the padlock in your browser is backed by point addition.
  • Messaging: Signal, WhatsApp and iMessage build their end-to-end encryption on Curve25519 key agreement.
  • Cryptocurrency: Bitcoin and Ethereum sign transactions with ECDSA over secp256k1 — your wallet is a secret multiplier.
  • Logins and devices: SSH keys, passkeys and smart cards favour ECC because small keys mean fast operations on constrained hardware.

The same one-way structure shows up across cryptography: the hardness of factoring guards RSA, and lattice problems like the shortest vector are the leading candidates for a post-quantum replacement once large quantum computers arrive.

Conclusion

Elliptic-curve cryptography turns a piece of nineteenth-century geometry into a twenty-first-century lock. Adding points with a ruler is fast; running the film backwards — recovering the multiplier — is the elliptic-curve discrete-log problem, and after forty years no one has found an efficient classical way to do it.

But notice the careful wording. ECC is not proven unbreakable; it is believed hard, in the same uneasy way as the questions behind P vs NP. And Shor's algorithm already breaks it in theory, waiting only for the hardware. The next time your browser shows a padlock, it is trusting a curve — and the bet that no one, classically, can walk that one-way street backwards.

Share this article

Pick a channel — or use your device's native share sheet.

Comments

Loading comments...

https://www.kipuhub.com/en/article/elliptic-curve-crypto/Content licensed under CC BY-NC 4.0.