{"record":{"id":"0d853deb2d41b54a","repo":"golang/go","slug":"mlkem-invalid-nist-decapsulation-key-length-0d853d","errorCode":null,"errorMessage":"mlkem: invalid NIST decapsulation key length","messagePattern":"mlkem: invalid NIST decapsulation key length","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/mlkem/mlkem768.go","lineNumber":223,"sourceCode":"\t\treturn nil, errors.New(\"mlkem: invalid seed length\")\n\t}\n\td := (*[32]byte)(seed[:32])\n\tz := (*[32]byte)(seed[32:])\n\tkemKeyGen(dk, d, z)\n\tfips140.RecordApproved()\n\treturn dk, nil\n}\n\n// TestingOnlyNewDecapsulationKey768 parses a decapsulation key from its expanded NIST format.\n//\n// Bytes() must not be called on the returned key, as it will not produce the\n// original seed.\n//\n// This function should only be used for ACVP testing. Prefer NewDecapsulationKey768 for all\n// other purposes.\nfunc TestingOnlyNewDecapsulationKey768(b []byte) (*DecapsulationKey768, error) {\n\tif len(b) != decapsulationKeySize768 {\n\t\treturn nil, errors.New(\"mlkem: invalid NIST decapsulation key length\")\n\t}\n\n\tdk := &DecapsulationKey768{}\n\tfor i := range dk.s {\n\t\tvar err error\n\t\tdk.s[i], err = polyByteDecode[nttElement](b[:encodingSize12])\n\t\tif err != nil {\n\t\t\treturn nil, errors.New(\"mlkem: invalid secret key encoding\")\n\t\t}\n\t\tb = b[encodingSize12:]\n\t}\n\n\tek, err := NewEncapsulationKey768(b[:EncapsulationKeySize768])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdk.ρ = ek.ρ\n\tdk.h = ek.h","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/mlkem/mlkem768.go#L205-L241","documentation":"Thrown by TestingOnlyNewDecapsulationKey768 when the input byte slice is not exactly decapsulationKeySize768 bytes. This is the NIST expanded-format constructor used only for ACVP testing; it rejects wrong-size blobs before any coefficient decode.","triggerScenarios":"Passing a 1024-size expanded blob to the 768 constructor, a seed (64 bytes) instead of the expanded format, or a truncated/transport-wrapped blob.","commonSituations":"Cross-parameter-set confusion, mistaking the seed path for the expanded path, or handing an ACVP vector with the trailing fields stripped.","solutions":["Verify the blob length is decapsulationKeySize768 before calling.","Confirm the blob is the NIST expanded format, not the 64-byte d||z seed (use NewDecapsulationKey768 for the seed).","Use the matching constructor for the ML-KEM parameter set indicated by the vector.","Re-obtain the vector from a vetted ACVP source for ML-KEM-768."],"exampleFix":"// before\ndk, err := mlkem768.TestingOnlyNewDecapsulationKey768(blob) // blob is for 1024\n// after\nif len(blob) != mlkem768.DecapsulationKeySize768() {\n    return fmt.Errorf(\"need ML-KEM-768 expanded blob of %d bytes\", mlkem768.DecapsulationKeySize768())\n}\ndk, err := mlkem768.TestingOnlyNewDecapsulationKey768(blob)","handlingStrategy":"validation","validationCode":"if len(b) != mlkem768.DecapsulationKeySize768() {\n    return fmt.Errorf(\"len %d != %d\", len(b), mlkem768.DecapsulationKeySize768())\n}","typeGuard":"func isLikelyMLKEM768Blob(b []byte) bool {\n    return len(b) == mlkem768.DecapsulationKeySize768()\n}","tryCatchPattern":"dk, err := mlkem768.TestingOnlyNewDecapsulationKey768(b)\nif err != nil {\n    return fmt.Errorf(\"ACVP vector rejected (param=768, len=%d): %w\", len(b), err)\n}","preventionTips":["Use NewDecapsulationKey768 with a 64-byte seed for non-ACVP use.","Tag persisted vectors with their ML-KEM parameter set.","Do not conflate the 64-byte seed path with the expanded NIST format path."],"tags":["mlkem","post-quantum","fips140","crypto","key-parsing","acvp","input-validation"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}