golang/go · error
unsupported curve
Error message
unsupported curve
What it means
NewHybridPublicKey only recognises X25519, P-256, and P-384 for the post-quantum hybrids defined in draft-ietf-hpke-pq. The default branch of its curve switch returns this error for any other curve, notably P-521.
Source
Thrown at src/crypto/hpke/pq.go:160
func NewHybridPublicKey(pq crypto.Encapsulator, t *ecdh.PublicKey) (PublicKey, error) {
switch t.Curve() {
case ecdh.X25519():
if _, ok := pq.(*mlkem.EncapsulationKey768); !ok {
return nil, errors.New("invalid PQ KEM for X25519 hybrid")
}
return &hybridPublicKey{mlkem768X25519, t, pq}, nil
case ecdh.P256():
if _, ok := pq.(*mlkem.EncapsulationKey768); !ok {
return nil, errors.New("invalid PQ KEM for P-256 hybrid")
}
return &hybridPublicKey{mlkem768P256, t, pq}, nil
case ecdh.P384():
if _, ok := pq.(*mlkem.EncapsulationKey1024); !ok {
return nil, errors.New("invalid PQ KEM for P-384 hybrid")
}
return &hybridPublicKey{mlkem1024P384, t, pq}, nil
default:
return nil, errors.New("unsupported curve")
}
}
func (kem *hybridKEM) NewPublicKey(data []byte) (PublicKey, error) {
if len(data) != kem.pqEncapsKeySize+kem.curvePointSize {
return nil, errors.New("invalid public key size")
}
pq, err := kem.pqNewPublicKey(data[:kem.pqEncapsKeySize])
if err != nil {
return nil, err
}
var k *ecdh.PublicKey
fips140.WithoutEnforcement(func() { // Hybrid of ML-KEM, which is Approved.
k, err = kem.curve.NewPublicKey(data[kem.pqEncapsKeySize:])
})
if err != nil {
return nil, err
}View on GitHub (pinned to b6b368adc5)
Solutions
- Use one of X25519, P-256, or P-384 for hybrid PQ keys.
- Switch to a non-hybrid KEM (e.g. DHKEM(P-521)) if P-521 is mandatory.
- Validate pub.Curve() before constructing the hybrid key.
Example fix
// before pub, _ := ecdh.P521().NewPublicKey(raw) hpkePub, err := hpke.NewHybridPublicKey(pq, pub) // "unsupported curve" // after pub, _ := ecdh.P384().NewPublicKey(raw) hpkePub, err := hpke.NewHybridPublicKey(pq, pub)
Defensive patterns
Strategy: validation
Validate before calling
func hybridSupportedCurve(c ecdh.Curve) bool {
switch c {
case ecdh.X25519(), ecdh.P256(), ecdh.P384():
return true
}
return false
}
func newHybridPub(pq crypto.Encapsulator, t *ecdh.PublicKey) (hpke.PublicKey, error) {
if !hybridSupportedCurve(t.Curve()) {
return nil, fmt.Errorf("hybrid PQ KEM does not support curve %v", t.Curve())
}
return hpke.NewHybridPublicKey(pq, t)
} Type guard
func isHybridCapable(pub *ecdh.PublicKey) bool {
switch pub.Curve() {
case ecdh.X25519(), ecdh.P256(), ecdh.P384():
return true
}
return false
} Try / catch
pub, err := hpke.NewHybridPublicKey(pq, t)
if err != nil && err.Error() == "unsupported curve" {
return nil, fmt.Errorf("hybrid needs X25519/P-256/P-384, got %v", t.Curve())
} Prevention
- Filter curves before constructing hybrid keys.
- Keep P-521 confined to classical-only DHKEM.
- Add a CI matrix that exercises each supported hybrid combiner.
When it happens
Trigger: Calling hpke.NewHybridPublicKey(pq, pub) where pub.Curve() is ecdh.P521() or any curve outside the three supported.
Common situations: Selecting P-521 expecting PQ support; reusing a classical-only key for a hybrid context; future curves added to crypto/ecdh.
Related errors
- invalid PQ KEM for X25519 hybrid
- invalid PQ KEM for P-256 hybrid
- invalid PQ KEM for P-384 hybrid
- invalid public key size
- hpke: invalid hybrid KEM secret length
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/6b4a598f47294c1e.
Report an issue: GitHub.