P-256 vs P-384 is a choice between two NIST curves of the same family: same algorithms (ECDSA and ECDH), same encodings, same tooling. P-384 raises classical security from about 128 to about 192 bits; P-256 is several times faster and supported by more hardware. For most systems the decision comes down to policy rather than risk.
At a glance
| P-256 (secp256r1) | P-384 (secp384r1) | |
|---|---|---|
| Field size, group order | 256 bits | 384 bits |
| Classical security | about 128 bits (AES-128 level) | about 192 bits (AES-192 level) |
| Usual hash | SHA-256 | SHA-384 |
| Private key | 32 bytes | 48 bytes |
| Public key | 65 bytes uncompressed, 91 as SPKI DER | 97 bytes uncompressed, 120 as SPKI DER |
| Signature | 64 bytes raw, 70–72 DER | 96 bytes raw, about 102–104 DER |
| Sign / verify per second, OpenSSL 3.6.5 | about 87,000 / 29,000 | about 9,700 / 4,500 |
| JOSE / COSE | ES256 / −7 | ES384 / −35 |
| TLS 1.3 | ecdsa_secp256r1_sha256 (0x0403), group 23 | ecdsa_secp384r1_sha384 (0x0503), group 24 |
| Hybrid TLS group | SecP256r1MLKEM768 | SecP384r1MLKEM1024 |
| Secure Enclave, Android Keystore, TPM 2.0 | Yes | Varies (not Secure Enclave) |
| NIST IR 8547 (draft) | disallowed after 2035 | disallowed after 2035 |
Speeds measured on one core of an Apple M4 Max with openssl speed; the size script below ran with OpenSSL 3.6.5.
How much security do you need?
NIST SP 800-57 Part 1 places curves of 256–383 bits at 128-bit security and 384–511 bits at 192-bit. 128 bits is far beyond any foreseeable classical attack: the best known attack on P-256 needs on the order of 2¹²⁸ group operations. P-384's extra margin protects against unexpected cryptanalytic progress on elliptic curves, not against brute force, and it does nothing against Shor's algorithm, which breaks both curves with similar effort. NIST IR 8547 (an initial public draft) therefore treats them the same: neither is deprecated in 2030 (that applies only to 112-bit algorithms such as RSA-2048 and P-224), and both are disallowed after 2035.
Policy is the real driver. The NSA's original Commercial National Security Algorithm Suite (CNSA 1.0) required P-384 for ECDH and ECDSA, so products for US national security systems and their supply chains default to it; CNSA 2.0 replaces it with ML-KEM-1024 and ML-DSA-87. Certificate authorities often choose P-384 for root and intermediate keys that must stay trustworthy for a decade or more; Let's Encrypt's ISRG Root X2 and its ECDSA intermediates are P-384 while subscriber certificates can use either curve.
Performance and size cost
OpenSSL ships hand-optimized assembly for P-256, which is why the gap is large: about 87,000 P-256 signatures per second against about 9,700 for P-384 on one Apple M4 Max core, and about 29,000 against 4,500 verifications. For a TLS server, the certificate key signs once per full handshake, so P-384 multiplies that part of the handshake cost by roughly nine; for a certificate authority signing a few certificates per second, it is irrelevant.
Sizes grow modestly: signatures by 32 bytes raw, public keys by 32 bytes, certificates by about 60 bytes.
#!/bin/sh
dir=$(mktemp -d)
cd "$dir" || exit 1
printf 'hello' > msg
for curve in P-256 P-384; do
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:$curve -out key.pem 2>/dev/null
openssl req -new -x509 -key key.pem -subj "/CN=example.com" -days 90 -outform DER -out cert.der 2>/dev/null
openssl dgst -sha256 -sign key.pem -out sig.der msg
printf '%s: SPKI %s bytes, DER signature %s bytes, self-signed certificate %s bytes\n' "$curve" \
"$(openssl pkey -in key.pem -pubout -outform DER | wc -c | tr -d ' ')" \
"$(wc -c < sig.der | tr -d ' ')" \
"$(wc -c < cert.der | tr -d ' ')"
done
cd / && rm -rf "$dir"
P-256: SPKI 91 bytes, DER signature 71 bytes, self-signed certificate 388 bytes
P-384: SPKI 120 bytes, DER signature 102 bytes, self-signed certificate 451 bytes
Support
Both curves are in FIPS 186-5 and SP 800-186, in every TLS library, in WebCrypto, in JOSE and COSE, in PIV smart cards and in the CA/Browser Forum's list of permitted certificate keys (P-256, P-384 and P-521). The gaps are in secure hardware and authenticators: Apple's Secure Enclave offers only P-256 for classical keys, passkeys use ES256 almost universally, and some IoT secure elements implement only P-256. On the server side, HSMs and cloud KMS services support both.
When to choose which
- Public TLS certificates: P-256. It is faster for handshakes and accepted everywhere; P-384 leaf certificates gain nothing a client can verify.
- CA root and intermediate keys: P-384 is a common, reasonable choice for long-lived keys; it may sign P-256 leaf certificates.
- JWT and API tokens:
ES256, unless a profile such as some government or financial specifications requiresES384. - Passkeys and device keys: P-256, because that is what the hardware offers.
- CNSA 1.0 systems and their vendors: P-384 with SHA-384, and AES-256; plan the move to ML-KEM-1024 and ML-DSA-87 under CNSA 2.0.
- Hybrid post-quantum TLS:
X25519MLKEM768for general use;SecP384r1MLKEM1024where a CNSA-style policy demands NIST curves and category 5 parameters.
Migration notes
Changing curves means new keys, but the tooling stays the same.
- Generate the new key with
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-384(or P-256) inside the HSM or KMS where it will live. - Pair the hash correctly. P-384 is normally used with SHA-384 (
ES384,ecdsa-with-SHA384); ECDSA truncates longer hashes to the order's length, but mismatched pairs confuse policy checks and some verifiers. - Update identifiers: JOSE
algandcrv, COSE algorithm, TLS signature scheme and certificate profiles. Publish both keys in a JWKS with separatekidvalues during rotation. - Resize fixed buffers: raw signatures grow from 64 to 96 bytes, coordinates from 32 to 48 bytes.
- Benchmark handshakes before switching a busy TLS endpoint to a P-384 certificate; most deployments that move to P-384 for policy reasons keep P-256 where the policy does not apply.