{"record":{"id":"6b4a598f47294c1e","repo":"golang/go","slug":"unsupported-curve-6b4a59","errorCode":null,"errorMessage":"unsupported curve","messagePattern":"unsupported curve","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/hpke/pq.go","lineNumber":160,"sourceCode":"func NewHybridPublicKey(pq crypto.Encapsulator, t *ecdh.PublicKey) (PublicKey, error) {\n\tswitch t.Curve() {\n\tcase ecdh.X25519():\n\t\tif _, ok := pq.(*mlkem.EncapsulationKey768); !ok {\n\t\t\treturn nil, errors.New(\"invalid PQ KEM for X25519 hybrid\")\n\t\t}\n\t\treturn &hybridPublicKey{mlkem768X25519, t, pq}, nil\n\tcase ecdh.P256():\n\t\tif _, ok := pq.(*mlkem.EncapsulationKey768); !ok {\n\t\t\treturn nil, errors.New(\"invalid PQ KEM for P-256 hybrid\")\n\t\t}\n\t\treturn &hybridPublicKey{mlkem768P256, t, pq}, nil\n\tcase ecdh.P384():\n\t\tif _, ok := pq.(*mlkem.EncapsulationKey1024); !ok {\n\t\t\treturn nil, errors.New(\"invalid PQ KEM for P-384 hybrid\")\n\t\t}\n\t\treturn &hybridPublicKey{mlkem1024P384, t, pq}, nil\n\tdefault:\n\t\treturn nil, errors.New(\"unsupported curve\")\n\t}\n}\n\nfunc (kem *hybridKEM) NewPublicKey(data []byte) (PublicKey, error) {\n\tif len(data) != kem.pqEncapsKeySize+kem.curvePointSize {\n\t\treturn nil, errors.New(\"invalid public key size\")\n\t}\n\tpq, err := kem.pqNewPublicKey(data[:kem.pqEncapsKeySize])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar k *ecdh.PublicKey\n\tfips140.WithoutEnforcement(func() { // Hybrid of ML-KEM, which is Approved.\n\t\tk, err = kem.curve.NewPublicKey(data[kem.pqEncapsKeySize:])\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/hpke/pq.go#L142-L178","documentation":"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.","triggerScenarios":"Calling hpke.NewHybridPublicKey(pq, pub) where pub.Curve() is ecdh.P521() or any curve outside the three supported.","commonSituations":"Selecting P-521 expecting PQ support; reusing a classical-only key for a hybrid context; future curves added to crypto/ecdh.","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."],"exampleFix":"// before\npub, _ := ecdh.P521().NewPublicKey(raw)\nhpkePub, err := hpke.NewHybridPublicKey(pq, pub) // \"unsupported curve\"\n\n// after\npub, _ := ecdh.P384().NewPublicKey(raw)\nhpkePub, err := hpke.NewHybridPublicKey(pq, pub)","handlingStrategy":"validation","validationCode":"func hybridSupportedCurve(c ecdh.Curve) bool {\n    switch c {\n    case ecdh.X25519(), ecdh.P256(), ecdh.P384():\n        return true\n    }\n    return false\n}\n\nfunc newHybridPub(pq crypto.Encapsulator, t *ecdh.PublicKey) (hpke.PublicKey, error) {\n    if !hybridSupportedCurve(t.Curve()) {\n        return nil, fmt.Errorf(\"hybrid PQ KEM does not support curve %v\", t.Curve())\n    }\n    return hpke.NewHybridPublicKey(pq, t)\n}","typeGuard":"func isHybridCapable(pub *ecdh.PublicKey) bool {\n    switch pub.Curve() {\n    case ecdh.X25519(), ecdh.P256(), ecdh.P384():\n        return true\n    }\n    return false\n}","tryCatchPattern":"pub, err := hpke.NewHybridPublicKey(pq, t)\nif err != nil && err.Error() == \"unsupported curve\" {\n    return nil, fmt.Errorf(\"hybrid needs X25519/P-256/P-384, got %v\", t.Curve())\n}","preventionTips":["Filter curves before constructing hybrid keys.","Keep P-521 confined to classical-only DHKEM.","Add a CI matrix that exercises each supported hybrid combiner."],"tags":["hpke","post-quantum","hybrid","ecdh","go"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}