{"record":{"id":"c00f293113b52ff1","repo":"golang/go","slug":"mlkem-inconsistent-h-ek-in-encoded-bytes-c00f29","errorCode":null,"errorMessage":"mlkem: inconsistent H(ek) in encoded bytes","messagePattern":"mlkem: inconsistent H\\(ek\\) in encoded bytes","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/mlkem/mlkem768.go","lineNumber":246,"sourceCode":"\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\n\tdk.encryptionKey = ek.encryptionKey\n\tb = b[EncapsulationKeySize768:]\n\n\tif !bytes.Equal(dk.h[:], b[:32]) {\n\t\treturn nil, errors.New(\"mlkem: inconsistent H(ek) in encoded bytes\")\n\t}\n\tb = b[32:]\n\n\tcopy(dk.z[:], b)\n\n\t// Generate a random d value for use in Bytes(). This is a safety mechanism\n\t// that avoids returning a broken key vs a random key if this function is\n\t// called in contravention of the TestingOnlyNewDecapsulationKey768 function\n\t// comment advising against it.\n\tdrbg.Read(dk.d[:])\n\n\treturn dk, nil\n}\n\n// kemKeyGen generates a decapsulation key.\n//\n// It implements ML-KEM.KeyGen_internal according to FIPS 203, Algorithm 16, and\n// K-PKE.KeyGen according to FIPS 203, Algorithm 13. The two are merged to save","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/mlkem/mlkem768.go#L228-L264","documentation":"Thrown by TestingOnlyNewDecapsulationKey768 when the 32-byte H(ek) digest embedded in the NIST expanded blob does not match SHA3-256 of the encapsulation-key portion. The decapsulation key is inconsistent with its embedded public key. 768 analogue of error 381.","triggerScenarios":"Blob has correct length and decodable s-vector + ek, but the hash field was computed over a different ek, zeroed, or assembled from unrelated sources.","commonSituations":"Concatenating dk_seed || ek || H(ek) || z from separate keys, truncating the hash during transport, mixing parameter sets, or stale cached blobs after a key rotation.","solutions":["Re-derive the blob from one keypair so H(ek) is recomputed over the embedded ek bytes.","Precompute sha3.Sum256(ek) and compare to the stored hash field before calling.","Use NewDecapsulationKey768 with the 64-byte seed for self-consistent derivation.","Discard hand-assembled blobs; use vetted ACVP vectors."],"exampleFix":"// before\ndk, err := mlkem768.TestingOnlyNewDecapsulationKey768(assembled)\n// after\nh := sha3.New256(); h.Write(assembled[ekOff:ekOff+EncapsulationKeySize768])\nif !bytes.Equal(h.Sum(nil), assembled[hashOff:hashOff+32]) {\n    return errors.New(\"blob H(ek) inconsistent; regenerate\")\n}\ndk, err := mlkem768.TestingOnlyNewDecapsulationKey768(assembled)","handlingStrategy":"validation","validationCode":"// Pre-check the H(ek) field against the ek half of the 768 blob.\nh := sha3.New256(); h.Write(b[ekStart:ekStart+mlkem768.EncapsulationKeySize768])\nif !bytes.Equal(h.Sum(nil), b[hashStart:hashStart+32]) {\n    return errors.New(\"H(ek) inconsistent; regenerate blob\")\n}","typeGuard":"func blob768HashConsistent(b []byte) bool {\n    ekStart := 2*encodingSize12 // k=2 for 768? verify k for ML-KEM-768\n    h := sha3.New256(); h.Write(b[ekStart : ekStart+mlkem768.EncapsulationKeySize768])\n    return bytes.Equal(h.Sum(nil), b[ekStart+mlkem768.EncapsulationKeySize768:ekStart+mlkem768.EncapsulationKeySize768+32])\n}","tryCatchPattern":"dk, err := mlkem768.TestingOnlyNewDecapsulationKey768(b)\nif err != nil && strings.Contains(err.Error(), \"inconsistent H(ek)\") {\n    return errors.New(\"blob internally inconsistent; regenerate\")\n}","preventionTips":["Never hand-assemble the NIST expanded blob from parts of different keys.","Persist and reload from the 64-byte seed.","Treat an H(ek) mismatch as corruption, not a recoverable parse error."],"tags":["mlkem","post-quantum","fips140","crypto","integrity","key-parsing","acvp"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}