{"record":{"id":"eef8b4a28cea4d94","repo":"golang/go","slug":"invalid-pq-kem-for-p-384-hybrid","errorCode":null,"errorMessage":"invalid PQ KEM for P-384 hybrid","messagePattern":"invalid PQ KEM for P-384 hybrid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/hpke/pq.go","lineNumber":156,"sourceCode":"//\n// This function is meant for applications that already have instantiated\n// crypto/ecdh and crypto/mlkem public keys. Otherwise, applications should use\n// the [KEM.NewPublicKey] method of e.g. [MLKEM768X25519].\nfunc 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:])","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/hpke/pq.go#L138-L174","documentation":"NewHybridPublicKey builds an ML-KEM + ECDH hybrid. For P-384 the only valid pairing is ML-KEM-1024 (combiner ID 0x0051). If the pq argument is not *mlkem.EncapsulationKey1024, the constructor rejects it. Note this branch differs from X25519/P-256, which require the 768-bit variant.","triggerScenarios":"Calling hpke.NewHybridPublicKey(pq, p384Pub) with pq being *mlkem.EncapsulationKey768 or any non-EncapsulationKey1024 Encapsulator.","commonSituations":"Assuming all hybrids use ML-KEM-768; reusing the same PQ key across X25519/P-256/P-384 code paths; copy-paste between combiner variants.","solutions":["Pair P-384 only with *mlkem.EncapsulationKey1024.","Prefer MLKEM1024P384().NewPublicKey(data) for combined parsing.","Document the per-curve ML-KEM size requirement at the call site."],"exampleFix":"// before\npq, _ := mlkem.NewEncapsulationKey768(pqBytes)\nhpkePub, err := hpke.NewHybridPublicKey(pq, p384Pub) // \"invalid PQ KEM for P-384 hybrid\"\n\n// after\npq, _ := mlkem.NewEncapsulationKey1024(pqBytes)\nhpkePub, err := hpke.NewHybridPublicKey(pq, p384Pub)","handlingStrategy":"type-guard","validationCode":"func p384HybridPub(pq crypto.Encapsulator, t *ecdh.PublicKey) (hpke.PublicKey, error) {\n    if _, ok := pq.(*mlkem.EncapsulationKey1024); !ok {\n        return nil, fmt.Errorf(\"P-384 hybrid requires *mlkem.EncapsulationKey1024, got %T\", pq)\n    }\n    return hpke.NewHybridPublicKey(pq, t)\n}","typeGuard":"func isMLKEM1024Encapsulator(pq crypto.Encapsulator) bool {\n    _, ok := pq.(*mlkem.EncapsulationKey1024)\n    return ok\n}","tryCatchPattern":"pub, err := hpke.NewHybridPublicKey(pq, p384Pub)\nif err != nil && err.Error() == \"invalid PQ KEM for P-384 hybrid\" {\n    return nil, fmt.Errorf(\"need *mlkem.EncapsulationKey1024, got %T\", pq)\n}","preventionTips":["Remember P-384 is the only combiner that pairs with ML-KEM-1024.","Use MLKEM1024P384().NewPublicKey(blob) for parsing.","Document the per-combiner ML-KEM size at the integration boundary."],"tags":["hpke","post-quantum","ml-kem","hybrid","go"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}