{"record":{"id":"71d92ed97ff78a0e","repo":"golang/go","slug":"invalid-pq-kem-for-p-256-hybrid","errorCode":null,"errorMessage":"invalid PQ KEM for P-256 hybrid","messagePattern":"invalid PQ KEM for P-256 hybrid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/hpke/pq.go","lineNumber":151,"sourceCode":"//   - MLKEM1024-P384\n//\n// from draft-ietf-hpke-pq, depending on the underlying curve of t\n// ([ecdh.X25519], [ecdh.P256], or [ecdh.P384]) and the type of pq (either\n// *[mlkem.EncapsulationKey768] or *[mlkem.EncapsulationKey1024]).\n//\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 {","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/hpke/pq.go#L133-L169","documentation":"NewHybridPublicKey builds an ML-KEM + ECDH hybrid. For P-256 the only valid pairing is ML-KEM-768. If the pq argument is not *mlkem.EncapsulationKey768, the constructor rejects it. Same shape as the X25519/P-384 branches but for the P-256 combiner (ID 0x0050).","triggerScenarios":"Calling hpke.NewHybridPublicKey(pq, p256Pub) with pq being *mlkem.EncapsulationKey1024 or any non-EncapsulationKey768 Encapsulator.","commonSituations":"Mismatching ML-KEM parameter sets across hybrid variants; using a 1024-bit ML-KEM key where the 768-bit variant is required.","solutions":["Pair P-256 only with *mlkem.EncapsulationKey768.","Prefer MLKEM768P256().NewPublicKey(data) to parse both halves at once.","Add a compile-time type assertion in your wrapper to catch mismatches early."],"exampleFix":"// before\npq, _ := mlkem.NewEncapsulationKey1024(pqBytes)\nhpkePub, err := hpke.NewHybridPublicKey(pq, p256Pub) // \"invalid PQ KEM for P-256 hybrid\"\n\n// after\npq, _ := mlkem.NewEncapsulationKey768(pqBytes)\nhpkePub, err := hpke.NewHybridPublicKey(pq, p256Pub)","handlingStrategy":"type-guard","validationCode":"func p256HybridPub(pq crypto.Encapsulator, t *ecdh.PublicKey) (hpke.PublicKey, error) {\n    if _, ok := pq.(*mlkem.EncapsulationKey768); !ok {\n        return nil, fmt.Errorf(\"P-256 hybrid requires *mlkem.EncapsulationKey768, got %T\", pq)\n    }\n    return hpke.NewHybridPublicKey(pq, t)\n}","typeGuard":"func isMLKEM768Encapsulator(pq crypto.Encapsulator) bool {\n    _, ok := pq.(*mlkem.EncapsulationKey768)\n    return ok\n}","tryCatchPattern":"pub, err := hpke.NewHybridPublicKey(pq, p256Pub)\nif err != nil && err.Error() == \"invalid PQ KEM for P-256 hybrid\" {\n    return nil, fmt.Errorf(\"need *mlkem.EncapsulationKey768, got %T\", pq)\n}","preventionTips":["Keep a combiner-to-ML-KEM-size map and assert before constructing.","Use MLKEM768P256().NewPublicKey(blob) for parsing.","Add an integration test per combiner to lock the parameter set."],"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"}