{"record":{"id":"ab6ae34a08dcd7e5","repo":"golang/go","slug":"invalid-public-key-size","errorCode":null,"errorMessage":"invalid public key size","messagePattern":"invalid public key size","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/hpke/pq.go","lineNumber":166,"sourceCode":"\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}\n\treturn NewHybridPublicKey(pq, k)\n}\n\nfunc (pk *hybridPublicKey) KEM() KEM {\n\treturn pk.kem\n}","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/hpke/pq.go#L148-L184","documentation":"hybridKEM.NewPublicKey deserializes a combined hybrid public key blob (PQ encapsulation key || ECDH point). The total length must equal kem.pqEncapsKeySize + kem.curvePointSize, fixed by the chosen combiner. Any other length is rejected before any parsing.","triggerScenarios":"Calling MLKEM768X25519().NewPublicKey(data) (or the P256/P384 equivalents) with data whose length does not match the combiner's fixed sum. Triggered by truncation, trailing bytes, or mixing key formats from a different combiner.","commonSituations":"Sender used a different hybrid KEM than receiver; raw bytes were padded/stripped in transit; misreading the spec on byte layout.","solutions":["Ensure the blob is exactly pqEncapsKeySize + curvePointSize bytes for the chosen combiner.","Match sender and recipient KEM (e.g. both MLKEM768X25519).","Verify length on the wire before invoking NewPublicKey and emit a clearer framing error."],"exampleFix":"// before\n// data was truncated in transit\npub, err := hpke.MLKEM768X25519().NewPublicKey(data) // \"invalid public key size\"\n\n// after\nconst want = 1184 + 32 // ML-KEM-768 encapsulation key + X25519 point\nif len(data) != want {\n    return fmt.Errorf(\"hybrid pubkey: got %d want %d\", len(data), want)\n}\npub, err := hpke.MLKEM768X25519().NewPublicKey(data)","handlingStrategy":"validation","validationCode":"var hybridKeyLen = map[uint16]int{\n    0x647A: 1184 + 32, // MLKEM768-X25519\n    0x0050: 1184 + 65, // MLKEM768-P256\n    0x0051: 1568 + 97, // MLKEM1024-P384\n}\nfunc parseHybridPub(kemID uint16, data []byte) (hpke.PublicKey, error) {\n    want, ok := hybridKeyLen[kemID]\n    if !ok {\n        return nil, fmt.Errorf(\"unknown hybrid kem 0x%04x\", kemID)\n    }\n    if len(data) != want {\n        return nil, fmt.Errorf(\"hybrid pubkey length: got %d want %d\", len(data), want)\n    }\n    return hpke.NewKEM(kemID).NewPublicKey(data)\n}","typeGuard":null,"tryCatchPattern":"pub, err := kem.NewPublicKey(data)\nif err != nil && err.Error() == \"invalid public key size\" {\n    return nil, fmt.Errorf(\"framing mismatch: blob %d bytes does not match combiner layout\", len(data))\n}","preventionTips":["Length-prefix the serialized hybrid key on the wire and verify before parsing.","Tag blobs with their combiner ID so receiver and sender agree on layout.","Round-trip test Bytes()/NewPublicKey for every combiner."],"tags":["hpke","post-quantum","hybrid","validation","framing","go"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T11:17:21.771Z"}