Why Learn Elliptic Curve Cryptography?
Elliptic Curve Cryptography (ECC) is a public-key framework proposed independently by Neal Koblitz and Victor Miller in 1985. Where RSA relies on integer factorization and Diffie-Hellman on the discrete logarithm over finite fields, ECC rests on the Elliptic Curve Discrete Logarithm Problem (ECDLP). No sub-exponential algorithm is known for ECDLP, so a 256-bit ECC key matches the security of 3072-bit RSA — a huge win in compute, bandwidth, and memory.
That efficiency is why modern infrastructure has largely moved to ECC. TLS 1.3 key exchange is de facto ECDHE (X25519 / P-256), Bitcoin and Ethereum sign with ECDSA over secp256k1, and SSH, Signal, and WireGuard use X25519 and Ed25519. The flip side is that the mathematics is one level more abstract than RSA or DH: “adding points” and “multiplying a point by an integer” take some getting used to.
This article works through the Weierstrass form, the geometry of point addition, ECDLP, a comparison of the major curves, and the ECDH / ECDSA protocols — then implements everything in Python in three stages: (1) point arithmetic from scratch, (2) production ECDH / ECDSA with cryptography.hazmat, and (3) X25519. For a bird’s-eye view of the cryptography landscape, see the
Cryptography Roadmap
.
Defining an Elliptic Curve
Over a field \(K\) of characteristic other than 2 or 3, an elliptic curve is the set of points \((x, y)\) satisfying the (short) Weierstrass form
\[ E: \; y^2 = x^3 + ax + b \quad (a, b \in K) \tag{1} \]together with the point at infinity \(\mathcal{O}\) . To rule out singular curves (cusps and self-intersections), the discriminant must be nonzero:
\[ \Delta = -16(4a^3 + 27b^2) \neq 0 \tag{2} \]If \(\Delta = 0\) , then \(x^3 + ax + b\) has a repeated root and the group structure below breaks down, making the curve useless for cryptography.
Cryptography does not use curves over the reals, but over a finite field \(\mathbb{F}_p\) for a prime \(p\) : \(E(\mathbb{F}_p)\) . By Hasse’s theorem the number of points satisfies
\[ |\#E(\mathbb{F}_p) - (p + 1)| \le 2\sqrt{p} \tag{3} \]so \(\#E(\mathbb{F}_p)\) is roughly \(p\) . Secure curves are designed so that \(\#E(\mathbb{F}_p) = h \cdot n\) with \(n\) a large prime and a small cofactor \(h\) (1, 4, or 8).
Point Addition and Doubling
The heart of ECC is a group law: adding two points on the curve yields another point on the curve. Geometrically it is the chord-and-tangent method:
- Addition \(P + Q\) : the line through distinct points \(P, Q\) meets the curve at a third point; reflect it across the \(x\) -axis to get \(P + Q\) .
- Doubling \(2P\) : the tangent at \(P\) meets the curve at one more point; its reflection is \(2P\) .
- Identity: the point at infinity \(\mathcal{O}\) , with \(P + \mathcal{O} = P\) and \(P + (-P) = \mathcal{O}\) (where \(-P\) is the mirror image of \(P\) ).

The figure above visualizes the chord-and-tangent method on a curve over the reals \(\mathbb{R}\) (the finite field \(\mathbb{F}_p\) used in cryptography is “a scattered finite set of points” and cannot be drawn directly, but the algebraic formulas (4) and (5) carry over unchanged). Panel (a) shows the chord through two points \(P, Q\) meeting the curve at one more point \(R\) , whose reflection across the \(x\) -axis is \(P + Q\) . Panel (b) shows the tangent at \(P\) meeting the curve at one more point, whose reflection is \(2P\) . The “chord slope \(\lambda\) ” and “tangent slope \(\lambda\) ” cases correspond exactly to equations (4) and (5).
With \(P = (x_1, y_1)\) , \(Q = (x_2, y_2)\) , and \(P + Q = (x_3, y_3)\) , the formulas use the line slope \(\lambda\) :
Addition (\(P \neq \pm Q\) ):
\[ \lambda = \frac{y_2 - y_1}{x_2 - x_1}, \quad x_3 = \lambda^2 - x_1 - x_2, \quad y_3 = \lambda(x_1 - x_3) - y_1 \tag{4} \]Doubling (\(P = Q\) , \(y_1 \neq 0\) ):
\[ \lambda = \frac{3x_1^2 + a}{2y_1}, \quad x_3 = \lambda^2 - 2x_1, \quad y_3 = \lambda(x_1 - x_3) - y_1 \tag{5} \]Over \(\mathbb{F}_p\)
, “division” becomes multiplication by the modular inverse mod \(p\)
, computable in Python as pow(x, -1, p) (extended Euclidean algorithm under the hood). The beauty of elliptic curves is that the geometric intuition over the reals transfers verbatim into the world of \(\bmod\, p\)
.
Under this operation, \(E(\mathbb{F}_p)\) forms an abelian group. Proving associativity is nontrivial, but cryptographic applications only need the group structure — in particular a cyclic subgroup of prime order \(n\) .
Scalar Multiplication and Double-and-Add
For a secret integer \(k\) and a base point \(G\) ,
\[ kG = \underbrace{G + G + \cdots + G}_{k \text{ times}} \tag{6} \]is called scalar multiplication. Since \(k\) is a 256-bit-scale integer, naive repeated addition is impossible; instead, double-and-add computes \(kG\) in \(O(\log k)\) point operations. It is exactly the additive-group analogue of binary exponentiation (exponentiation by squaring) :
| Multiplicative group (\(g^k \bmod p\) ) | Elliptic curve (\(kG\) ) |
|---|---|
| Squaring \(x \mapsto x^2\) | Doubling \(P \mapsto 2P\) |
| Multiplication \(x \cdot y\) | Point addition \(P + Q\) |
| Exponentiation by squaring | Double-and-add |
| DLP : find \(x\) from \(g^x = h\) | ECDLP: find \(k\) from \(kG = Q\) |
Scanning the binary expansion of \(k\) from the least significant bit — “add when the bit is 1, double every step” — handles a 256-bit \(k\) in at most 511 point operations. Note that naive double-and-add leaks the bit pattern of \(k\) through timing (side-channel attacks), so production implementations use constant-time algorithms such as the Montgomery ladder.
The Elliptic Curve Discrete Logarithm Problem (ECDLP)
ECC’s security rests on the hardness of inverting scalar multiplication:
\[ \text{given } Q = kG, \text{ recover } k \tag{7} \]This is the Elliptic Curve Discrete Logarithm Problem (ECDLP). The forward direction costs \(O(\log k)\) , but the best known inverse algorithm (Pollard’s rho) takes fully exponential time \(O(\sqrt{n})\) . Index calculus and the number field sieve — the tools that make finite-field DLP and factorization sub-exponential — do not apply to elliptic curves, which is why the same security level needs far shorter keys.
Equivalent-security comparison per NIST SP 800-57:
| Symmetric strength | RSA / DH key size | ECC key size | Notes |
|---|---|---|---|
| 80 bit | 1024 bit | 160 bit | Deprecated (legacy) |
| 112 bit | 2048 bit | 224 bit | Current minimum |
| 128 bit | 3072 bit | 256 bit | Modern standard (P-256) |
| 192 bit | 7680 bit | 384 bit | P-384 |
| 256 bit | 15360 bit | 512 bit | Long-term / high security |
A 256-bit ECC key is equivalent to a 3072-bit RSA key. The ratio widens with the security level: 12x at 128-bit strength, 30x at 256-bit. This is why ECC dominates wherever signature size, handshake bandwidth, or embedded memory matters. Like RSA and DH, however, ECDLP falls to Shor’s algorithm on a quantum computer, so migration to post-quantum cryptography (PQC) is underway in parallel (see the Cryptography Roadmap ).

The chart makes one fact obvious: the key-size ratio widens faster than linearly as the security level rises. This traces directly to the complexity gap between the two best-known attacks.
- ECDLP (Pollard’s rho): fully exponential time \(O(\sqrt{n})\) . To reach \(\kappa\) bits of symmetric strength, an order \(n \approx 2^{2\kappa}\) — i.e. a key of roughly \(2\kappa\) bits — suffices. Indeed, across 80→256 bit, the ECC key sizes track \(2\kappa\) almost exactly (160, 224 (\(\approx 2\times112\) ), 256, 384, 512).
- RSA / DH (number field sieve, NFS): sub-exponential time \(L_N[1/3, (64/9)^{1/3}] = \exp\!\big((c+o(1))(\ln N)^{1/3}(\ln \ln N)^{2/3}\big)\) . Setting this equal to \(2^\kappa\) and solving for \(\ln N\) shows that \(\ln N\) (roughly proportional to key size) grows on the order of \(\kappa^3\) (not an exact cube law, due to the log-log term, but the dominant reason the key size grows faster and faster as \(\kappa\) increases).
The graph’s widening gap is exactly the visible consequence of ECDLP’s exponential hardness versus the sub-exponential hardness of finite-field DLP / integer factorization.
Major Curves Compared: P-256 / secp256k1 / Curve25519
The three curves you meet in practice:
| Aspect | P-256 (secp256r1) | secp256k1 | Curve25519 |
|---|---|---|---|
| Form | Short Weierstrass | Short Weierstrass (Koblitz) | Montgomery (\(y^2 = x^3 + 486662x^2 + x\) ) |
| Parameters | \(a = -3\) , pseudo-random \(b\) | \(a = 0\) , \(b = 7\) | \(p = 2^{255} - 19\) |
| Designer | NIST / NSA (1999) | SECG (2000) | Daniel J. Bernstein (2005) |
| Main uses | TLS, ECDSA certs, FIDO2 | Bitcoin / Ethereum signatures | X25519 key exchange, Ed25519 signatures |
| Strengths | Widest interoperability | Fast special prime, endomorphism speedup | Constant time, misuse resistance, clamping |
| Concerns | Opaque parameter provenance | Side-channel safety is implementation-dependent | Essentially none (misuse-resistant design) |
- P-256 is the de facto standard for TLS certificates and FIDO2 / WebAuthn. NIST curves are sometimes criticized for opaque parameter selection, but no vulnerability is known.
- secp256k1 is a Koblitz curve with \(a = 0\) over the special prime \(p = 2^{256} - 2^{32} - 977\) , making modular reduction fast. Satoshi Nakamoto’s choice for Bitcoin made it the blockchain standard.
- Curve25519 uses the Montgomery form, enabling an \(x\) -coordinate-only Montgomery ladder that is always constant-time. Invalid-curve and low-order-subgroup attacks are eliminated by design; it is the modern curve optimized for “hard to implement incorrectly.” See also the X25519 section of the Diffie-Hellman article .
ECDH Key Exchange and ECDSA Signatures
ECDH: Elliptic Curve Diffie-Hellman
ECDH replaces the \(g^a \bmod p\) of DH key exchange with the scalar multiplication \(aG\) :
- Alice picks a secret \(a \in [1, n-1]\) and sends the public key \(A = aG\) .
- Bob picks a secret \(b\) and sends \(B = bG\) .
- Both compute the shared point:
Commutativity of scalar multiplication, \(a(bG) = b(aG)\) , lands both parties on the same point \(abG\) ; its \(x\) -coordinate goes through HKDF to derive the session key. An eavesdropper cannot compute \(abG\) from \(A = aG\) and \(B = bG\) (the ECDH assumption). TLS 1.3 uses ephemeral keys each session — ECDHE — to provide forward secrecy .
ECDSA: Elliptic Curve Digital Signature Algorithm
ECDSA lets only the private-key holder sign while anyone can verify with the public key. Let \(d\) be the private key, \(Q = dG\) the public key, and \(e = H(m)\) the message hash.
Signing:
- Pick a one-time random nonce \(k \in [1, n-1]\) .
- Compute \(R = kG\) and \(r = R_x \bmod n\) (retry if \(r = 0\) ).
- Compute \(s = k^{-1}(e + rd) \bmod n\) (retry if \(s = 0\) ). The signature is \((r, s)\) .
Verification:
\[ u_1 = e s^{-1} \bmod n, \quad u_2 = r s^{-1} \bmod n, \quad (x, y) = u_1 G + u_2 Q \tag{10} \]Accept if \(x \bmod n = r\) . Correctness follows from \(u_1 G + u_2 Q = s^{-1}(e + rd) G = kG = R\) .
ECDSA’s biggest pitfall is nonce reuse or bias. Signing two messages with the same \(k\) lets an attacker solve a pair of linear equations and recover the private key \(d\) instantly — the 2010 PlayStation 3 signing-key leak is the classic incident. Modern implementations use deterministic nonces per RFC 6979 (derived via HMAC from \(d\) and \(H(m)\) ), structurally preventing this failure. Ed25519 (EdDSA) is the successor that reduces reliance on randomness even further.
Python Implementation
1. From Scratch: Point Addition and Scalar Multiplication over \(\mathbb{F}_p\)
First, with no external libraries, we implement point arithmetic on secp256k1 exactly as in equations (4) and (5). Inverses use pow(x, -1, p), scalar multiplication uses
double-and-add
.
import hashlib
# --- secp256k1 domain parameters ---
p = 2**256 - 2**32 - 977 # prime of the base field
a, b = 0, 7 # y^2 = x^3 + 7
Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
Gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
G = (Gx, Gy)
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 # order of G
assert (-16 * (4 * a**3 + 27 * b**2)) % p != 0 # discriminant condition (2)
O = None # point at infinity (identity)
def ec_add(P, Q):
"""Point addition on the curve: implements equations (4), (5)."""
if P is O:
return Q
if Q is O:
return P
x1, y1 = P
x2, y2 = Q
if x1 == x2 and (y1 + y2) % p == 0:
return O # P + (-P) = O
if P == Q:
lam = (3 * x1 * x1 + a) * pow(2 * y1, -1, p) % p # tangent slope
else:
lam = (y2 - y1) * pow(x2 - x1, -1, p) % p # chord slope
x3 = (lam * lam - x1 - x2) % p
y3 = (lam * (x1 - x3) - y1) % p
return (x3, y3)
def scalar_mult(k, P):
"""k*P via double-and-add: O(log k) point operations."""
R, Q = O, P
while k:
if k & 1:
R = ec_add(R, Q) # add when the bit is 1
Q = ec_add(Q, Q) # double every step
k >>= 1
return R
def is_on_curve(P):
if P is O:
return True
x, y = P
return (y * y - (x**3 + a * x + b)) % p == 0
# --- ECDH demo (private keys derived from a fixed SHA-256 seed for reproducibility;
# use secrets.randbelow(n - 1) + 1 in production) ---
alice_priv = int.from_bytes(hashlib.sha256(b"ecc-demo-alice-seed").digest(), "big") % (n - 1) + 1
bob_priv = int.from_bytes(hashlib.sha256(b"ecc-demo-bob-seed").digest(), "big") % (n - 1) + 1
alice_pub = scalar_mult(alice_priv, G) # A = aG
bob_pub = scalar_mult(bob_priv, G) # B = bG
assert is_on_curve(alice_pub) and is_on_curve(bob_pub)
shared_alice = scalar_mult(alice_priv, bob_pub) # aB = abG
shared_bob = scalar_mult(bob_priv, alice_pub) # bA = abG
assert shared_alice == shared_bob
print(f"Shared secret x-coordinate: {hex(shared_alice[0])[:18]}...")
Actual output:
Shared secret x-coordinate: 0xd9c78f242d749447...
(Full value: 0xd9c78f242d749447061adf7c4dc4220b9e8012a90f2ad3d7383b227f98ca9222. The assert confirms shared_alice and shared_bob, computed independently by Alice and Bob, are equal.)
Three notes:
- Modular inverses via
pow(x, -1, p): Python 3.8+ computes modular inverses with the built-inpow. Every “division” in \(\mathbb{F}_p\) reduces to this. scalar_multis isomorphic to binary exponentiation : read “squaring → doubling” and “multiplication → point addition”; the code structure is identical.- This implementation is educational only: its running time depends on the secret key (side-channel weakness), and invalid-curve checks (
is_on_curveon every received point, subgroup checks) are minimal. Usecryptographyin production.
2. Production Library: ECDH / ECDSA with cryptography.hazmat
Production code should use the vetted cryptography.hazmat.primitives.asymmetric.ec module. Just pick a curve such as ec.SECP256R1() (P-256) or ec.SECP256K1().
import hashlib
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives import hashes
from cryptography.exceptions import InvalidSignature
# --- ECDH (P-256): private keys derived from a fixed seed for reproducibility
# (use generate_private_key() in production) ---
alice_scalar = int.from_bytes(hashlib.sha256(b"ecc-demo-alice-seed").digest(), "big")
bob_scalar = int.from_bytes(hashlib.sha256(b"ecc-demo-bob-seed").digest(), "big")
alice_private = ec.derive_private_key(alice_scalar, ec.SECP256R1())
bob_private = ec.derive_private_key(bob_scalar, ec.SECP256R1())
alice_shared = alice_private.exchange(ec.ECDH(), bob_private.public_key())
bob_shared = bob_private.exchange(ec.ECDH(), alice_private.public_key())
assert alice_shared == bob_shared
# Never use the raw shared secret directly; derive a session key with HKDF-SHA256
session_key = HKDF(
algorithm=hashes.SHA256(),
length=32,
salt=None,
info=b"ecdh handshake",
).derive(alice_shared)
print(f"Shared secret (raw, hex): {alice_shared.hex()}")
print(f"Session key: {session_key.hex()[:32]}...")
# --- ECDSA (secp256k1): signing key also derived from a fixed seed ---
signing_scalar = int.from_bytes(hashlib.sha256(b"ecc-demo-signing-seed").digest(), "big")
signing_key = ec.derive_private_key(signing_scalar, ec.SECP256K1())
message = b"transfer 1 BTC to Bob"
signature = signing_key.sign(message, ec.ECDSA(hashes.SHA256()))
# Verification raises InvalidSignature on failure
try:
signing_key.public_key().verify(signature, message, ec.ECDSA(hashes.SHA256()))
print("Signature valid")
except InvalidSignature:
print("Signature invalid")
Actual output:
Shared secret (raw, hex): d2bea85e89065193393f43443bad4fbedefa09b3820806af57746e714b78d3d6
Session key: 15b98c565be15e0d033afb34a014ffe5...
Signature valid
cryptography’s exchange() automatically validates that incoming public keys lie on the curve. Its sign() nonce generation deserves a caveat: by default, cryptography (OpenSSL backend) generates ECDSA nonces with a CSPRNG, not RFC 6979 deterministic nonces (running the code above twice, with the same key and message, produces a different signature byte string each time). If you need deterministic signatures, use EdDSA (Ed25519), or explicitly wire in an RFC 6979 implementation. Absorbing the classic landmines of hand-rolled code — nonce reuse, invalid-curve attacks — at the library layer is still exactly why you should use it in production.
3. X25519: The Modern Default Key Exchange
X25519
— adopted by TLS 1.3, SSH, Signal, and WireGuard — lives in the dedicated module cryptography.hazmat.primitives.asymmetric.x25519. The API is minimal: there is not even a curve to choose.
import hashlib
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives import hashes
# Derive 32-byte private keys from a fixed seed for reproducibility
# (use X25519PrivateKey.generate() in production)
alice_bytes = hashlib.sha256(b"x25519-demo-alice-seed").digest()
bob_bytes = hashlib.sha256(b"x25519-demo-bob-seed").digest()
alice_private = X25519PrivateKey.from_private_bytes(alice_bytes)
bob_private = X25519PrivateKey.from_private_bytes(bob_bytes)
alice_shared = alice_private.exchange(bob_private.public_key())
bob_shared = bob_private.exchange(alice_private.public_key())
assert alice_shared == bob_shared
session_key = HKDF(
algorithm=hashes.SHA256(),
length=32,
salt=None,
info=b"x25519 handshake",
).derive(alice_shared)
print(f"X25519 shared secret (raw, hex): {alice_shared.hex()}")
print(f"X25519 session key: {session_key.hex()[:32]}...")
Actual output:
X25519 shared secret (raw, hex): a008086abfda856f09f027cd151fb953237b3b682d57190b5d5e5db527ce4a21
X25519 session key: f458ca9bd1c192b2b67a7cadc65c05cd...
X25519 public keys and shared secrets are always exactly 32 bytes, and clamping eliminates low-order-subgroup attacks by design. “Use X25519 for any new protocol’s key exchange” is the 2026 best practice. If you need signatures, use its sibling Ed25519 (cryptography.hazmat.primitives.asymmetric.ed25519).
2024-2026 Trend: Hybrid Key Exchange with X25519 + ML-KEM
Because ECDLP is theoretically broken by Shor’s algorithm on a quantum computer, TLS 1.3 key exchange is migrating to a hybrid scheme that runs classical ECDH alongside a post-quantum KEM in parallel. The IETF’s draft-ietf-tls-ecdhe-mlkem (approved as a Proposed Standard as of 2026) defines a concrete combination named X25519MLKEM768: the client’s key-share value concatenates the ML-KEM-768 encapsulation key (1184 bytes) with an ephemeral X25519 public key (32 bytes) for 1216 bytes total, and the shared secret concatenates 32 bytes from each component for 64 bytes. Chrome 131 (November 2024) and Firefox 135 (February 2025) support it by default, and Cloudflare measured roughly 38% of its network’s HTTPS traffic using hybrid PQC as of March 2025. The key design point is that X25519 is not replaced but paired with ML-KEM: if a future weakness is found in ML-KEM, X25519’s classical security still holds, and if quantum computers become practical, ML-KEM still protects the exchange — a conservative “secure unless both are broken” migration strategy.
Summary
- An elliptic curve is defined by the Weierstrass form \(y^2 = x^3 + ax + b\) with discriminant condition \(-16(4a^3 + 27b^2) \neq 0\) , and the chord-and-tangent method makes it an abelian group.
- Scalar multiplication \(kG\) reduces to \(O(\log k)\) point operations via double-and-add, which is exactly isomorphic to binary exponentiation .
- Security rests on ECDLP; since index calculus does not apply, 256-bit ECC ≈ 3072-bit RSA .
- The major curves are P-256 (TLS / FIDO2), secp256k1 (Bitcoin / Ethereum), and Curve25519 (X25519 / Ed25519) — pick per use case.
- ECDH works by commutativity \(abG\) ; ECDSA by the signing/verification equations (9), (10). Nonce reuse directly leaks the private key.
- In Python: implement from scratch (
pow(x, -1, p)+ double-and-add) to learn; usecryptography.hazmat’sec/x25519modules in production. - ECC also falls to Shor’s algorithm on quantum computers; hybrid PQC schemes like X25519MLKEM768 are rolling out across Chrome, Firefox, and Cloudflare in 2024-2026 — see the Cryptography Roadmap .
Related Articles
- Cryptography Roadmap: DLP, Factorization, Elliptic Curves to PQC - The learning map for the whole cryptography space; this article deep-dives its elliptic-curve part.
- Diffie-Hellman Key Exchange in Depth - The finite-field DH in detail; ECDH is its elliptic-curve version.
- Post-Quantum Cryptography in Python: Learning With Errors (LWE) and Regev Encryption - Explains why this article’s ECDLP is broken by Shor’s algorithm on a quantum computer, and the migration to the quantum-resistant LWE problem.
- Dissecting the TLS 1.3 Handshake in Python - Implements how this article’s ECDHE (X25519) is used in an actual protocol and folded into the HKDF key schedule.
- Understanding SSH Key Exchange Through Diffie-Hellman and Elliptic Curve Cryptography
- Implements how this article’s X25519 is used in SSH as
curve25519-sha256, and how it feeds into RFC 4253’s session key derivation. - RSA Encryption Theory, Key Generation, Encryption, and Decryption in Python - The factorization-based public-key system, the other side of the key-size comparison.
- Fast Modular Exponentiation Using Binary Exponentiation in Python - The multiplicative-group version of double-and-add; a prerequisite for scalar multiplication.
- Elliptic Curve ElGamal Encryption: Principles and Simplified Python Implementation - Encryption on elliptic curves, a neighbor of ECDH / ECDSA.
- Diffie-Hellman Key Exchange Protocol: Theory and Python Implementation - The introductory DH article, good for forward-secrecy basics.
- AES and ChaCha20 in Python - Where the ECDH-derived session key ends up: AES-GCM / ChaCha20-Poly1305 AEAD and nonce handling in depth.
- Digital Signatures (ECDSA / EdDSA / RSA-PSS) in Python - Deep-dives the ECDSA / EdDSA signature schemes from this article, including nonce-reuse attacks and deterministic signing (RFC 6979).
- OAuth 2.0 and OpenID Connect: Fundamentals - Where ECDSA signatures (ES256) show up in JWTs in practice.
- Zero Trust Architecture: Principles, Components, and Implementation - Plugging ECC-based PKI / mTLS into organization-level design.
- Security Certification Comparison: CISSP vs Japan’s Registered Information Security Specialist - Certifications whose exams cover ECC and modern cryptography.
Related Tools
- Hash Generator (DevToolBox) - Compute the message hash H(m) used by ECDSA
- Number Base Converter (CalcBox) - Inspect curve parameters in hexadecimal
References
- Koblitz, N. (1987). “Elliptic Curve Cryptosystems”. Mathematics of Computation, 48(177), 203–209.
- Miller, V. S. (1986). “Use of Elliptic Curves in Cryptography”. CRYPTO ‘85.
- Bernstein, D. J. (2006). “Curve25519: new Diffie-Hellman speed records”. PKC 2006.
- Hankerson, D., Menezes, A., & Vanstone, S. (2004). Guide to Elliptic Curve Cryptography. Springer.
- Pornin, T. (2013). “Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA)”. RFC 6979.
- NIST (2020). “Recommendation for Key Management: Part 1 – General”. SP 800-57 Part 1 Rev. 5.
- Certicom Research (2010). “SEC 2: Recommended Elliptic Curve Domain Parameters”. Version 2.0.
- IETF TLS Working Group (2026). “Post-Quantum Hybrid ECDHE-MLKEM Key Agreement for TLSv1.3”. draft-ietf-tls-ecdhe-mlkem-05. https://datatracker.ietf.org/doc/draft-ietf-tls-ecdhe-mlkem/
- netguardia.com (2025). “Hybrid Key Exchange Today: Why X25519 + ML-KEM Is the Interim Default”. https://netguardia.com/privacy/encryption/hybrid-key-exchange-today-why-x25519-ml-kem-is-the-interim-default/