{"record":{"id":"6afb982157785b88","repo":"golang/go","slug":"mlkem-invalid-polynomial-encoding","errorCode":null,"errorMessage":"mlkem: invalid polynomial encoding","messagePattern":"mlkem: invalid polynomial encoding","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/internal/fips140/mlkem/field.go","lineNumber":174,"sourceCode":"\treturn out\n}\n\n// polyByteDecode decodes the 384-byte encoding of a polynomial, checking that\n// all the coefficients are properly reduced. This fulfills the \"Modulus check\"\n// step of ML-KEM Encapsulation.\n//\n// It implements ByteDecode₁₂, according to FIPS 203, Algorithm 6.\nfunc polyByteDecode[T ~[n]fieldElement](b []byte) (T, error) {\n\tif len(b) != encodingSize12 {\n\t\treturn T{}, errors.New(\"mlkem: invalid encoding length\")\n\t}\n\tvar f T\n\tfor i := 0; i < n; i += 2 {\n\t\td := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16\n\t\tconst mask12 = 0b1111_1111_1111\n\t\tvar err error\n\t\tif f[i], err = fieldCheckReduced(uint16(d & mask12)); err != nil {\n\t\t\treturn T{}, errors.New(\"mlkem: invalid polynomial encoding\")\n\t\t}\n\t\tif f[i+1], err = fieldCheckReduced(uint16(d >> 12)); err != nil {\n\t\t\treturn T{}, errors.New(\"mlkem: invalid polynomial encoding\")\n\t\t}\n\t\tb = b[3:]\n\t}\n\treturn f, nil\n}\n\n// sliceForAppend takes a slice and a requested number of bytes. It returns a\n// slice with the contents of the given slice followed by that many bytes and a\n// second slice that aliases into it and contains only the extra bytes. If the\n// original slice has sufficient capacity then no allocation is performed.\nfunc sliceForAppend(in []byte, n int) (head, tail []byte) {\n\tif total := len(in) + n; cap(in) >= total {\n\t\thead = in[:total]\n\t} else {\n\t\thead = make([]byte, total)","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/internal/fips140/mlkem/field.go#L156-L192","documentation":"After confirming the 384-byte length, polyByteDecode unpacks each pair of coefficients (12 bits each) and calls fieldCheckReduced to ensure every value is < q (3329). A value ≥ 3329 means the encoding is non-canonical, which FIPS 203 explicitly forbids during decapsulation (the 'Modulus check' step); 'invalid polynomial encoding' is returned. This rejects malformed keys/ciphertexts that could leak information through non-canonical encodings.","triggerScenarios":"A 384-byte polynomial block whose bit-packed 12-bit words contain a value ≥ 3329 (the even-indexed coefficient of any pair).","commonSituations":"Corrupted ciphertext; a peer implementation that does not range-reduce coefficients; tampering intended to probe the decapsulator; bit flips in stored key material.","solutions":["Treat as an invalid ciphertext/key: return a decapsulation failure and, per FIPS 203, fall back to the implicit-rejection shared secret only if that is your protocol's policy.","Re-acquire the ciphertext from the peer; if reproducible, suspect a non-conformant peer implementation.","Add an integrity wrapper (AEAD/checksum) around stored ML-KEM blobs so corruption is caught before decapsulation."],"exampleFix":"// before\nss, err := dk.DecapsulateClient(ct)  // ct has a non-canonical coefficient\nif err != nil { panic(err) }\n\n// after\nss, err := dk.DecapsulateClient(ct)\nif err != nil { return ErrCiphertextInvalid }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if _, err := dk.DecapsulateClient(ct); err != nil {\n    return ErrCiphertextInvalid // do not distinguish modulus-check sub-failures\n}","preventionTips":["Wrap ML-KEM ciphertexts/keys in an integrity (AEAD/checksum) layer.","Treat any modulus-check failure as a decapsulation failure and apply your implicit-rejection policy.","Reject peers whose ciphertexts reproducibly fail the modulus check."],"tags":["crypto","mlkem","fips","verification","integrity"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}