Error message
java.security.InvalidAlgorithmParameterException: Curve not supported: secp256k1 (1.3.132.0.10)
Also printed as
- Legacy SunEC curve disabled
Thrown by `KeyPairGenerator.initialize`, `KeyFactory.generatePublic/Private` (wrapped in `InvalidKeySpecException`) and `Signature.initVerify`, depending on where the curve first appears. JDK 15 had already disabled these curves by default (JDK-8237219) with the message "Legacy SunEC curve disabled", re-enabled by `-Djdk.sunec.disableNative=false`; JDK 14 and earlier supported them.
Java (JDK 16+) — KeyPairGenerator / KeyFactory / Signature with the SunEC provider
What it means
The JDK knows the name secp256k1 (the curve used by Bitcoin and Ethereum) — it even resolves it to its OID 1.3.132.0.10 — but its built-in SunEC provider no longer implements it. JDK 16 removed the legacy curves together with the native EC library (release note "Removal of Legacy Elliptic Curves", JDK-8235710) and kept only curves with modern implementations: P-256, P-384, P-521, X25519/X448 and Ed25519/Ed448. Code that worked on Java 8 or 11 fails here after an upgrade.
Why it happens
Running on JDK 16 or newer
commonThe curve list of SunEC shrank in JDK 16. Upgrading the runtime of a blockchain-related service is the most common trigger.
ES256K JWTs or secp256k1 JWKs
occasionalJOSE libraries that delegate to JCA (for example Nimbus) need a provider with secp256k1 for `ES256K` (RFC 8812).
Code copied from a pre-2021 example
occasionalExamples that use `ECGenParameterSpec("secp256k1")` with the default provider predate the removal.
How to fix it
- 1.
Use the Bouncy Castle provider
Bouncy Castle implements secp256k1 in pure Java. Register it and request it explicitly with `"BC"`.
java import java.security.*; import java.security.spec.ECGenParameterSpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; Security.addProvider(new BouncyCastleProvider()); KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", "BC"); generator.initialize(new ECGenParameterSpec("secp256k1")); KeyPair pair = generator.generateKeyPair(); Signature signature = Signature.getInstance("SHA256withECDSA", "BC"); - 2.
For Ethereum work, use a library built for it
web3j and similar libraries handle secp256k1, recovery ids and EIP-191 prefixes for you, which plain JCA does not.
java // Ethereum signing/recovery: web3j implements secp256k1 itself (on top of Bouncy Castle). org.web3j.crypto.ECKeyPair keyPair = org.web3j.crypto.Keys.createEcKeyPair(); org.web3j.crypto.Sign.SignatureData sig = org.web3j.crypto.Sign.signPrefixedMessage(message, keyPair);