golang/go · error

mlkem: invalid ciphertext length

Error message

mlkem: invalid ciphertext length

What it means

Thrown by Decapsulate1024 when the ciphertext byte slice is not exactly CiphertextSize1024 bytes. Length is checked before the SHA3/decapsulation machinery runs; an off-size input cannot be a valid ML-KEM-1024 ciphertext.

Source

Thrown at src/crypto/internal/fips140/mlkem/mlkem1024.go:404

	v := polyAdd(polyAdd(inverseNTT(vNTT), e2), μ)

	c := cc[:0]
	for _, f := range u {
		c = ringCompressAndEncode11(c, f)
	}
	c = ringCompressAndEncode5(c, v)

	return c
}

// Decapsulate generates a shared key from a ciphertext and a decapsulation key.
// If the ciphertext is not valid, Decapsulate returns an error.
//
// The shared key must be kept secret.
func (dk *DecapsulationKey1024) Decapsulate(ciphertext []byte) (sharedKey []byte, err error) {
	fipsSelfTest()
	if len(ciphertext) != CiphertextSize1024 {
		return nil, errors.New("mlkem: invalid ciphertext length")
	}
	c := (*[CiphertextSize1024]byte)(ciphertext)
	// Note that the hash check (step 3 of the decapsulation input check from
	// FIPS 203, Section 7.3) is foregone as a DecapsulationKey is always
	// validly generated by ML-KEM.KeyGen_internal.
	return kemDecaps1024(dk, c), nil
}

// kemDecaps1024 produces a shared key from a ciphertext.
//
// It implements ML-KEM.Decaps_internal according to FIPS 203, Algorithm 18.
func kemDecaps1024(dk *DecapsulationKey1024, c *[CiphertextSize1024]byte) (K []byte) {
	fips140.RecordApproved()
	m := pkeDecrypt1024(&dk.decryptionKey1024, c)
	g := sha3.New512()
	g.Write(m[:])
	g.Write(dk.h[:])
	G := g.Sum(make([]byte, 0, 64))

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Assert len(ciphertext) == CiphertextSize1024 before calling Decapsulate.
  2. Confirm the ciphertext was produced by Encapsulate1024 against a 1024 encapsulation key.
  3. Strip any framing/header before passing the raw ciphertext.
  4. Decode base64/hex into a []byte of the expected length.

Example fix

// before
shared, err := dk.Decapsulate(ct) // ct is 768-size by mistake
// after
if len(ct) != mlkem1024.CiphertextSize1024 {
    return fmt.Errorf("ct len %d != %d", len(ct), mlkem1024.CiphertextSize1024)
}
shared, err := dk.Decapsulate(ct)
Defensive patterns

Strategy: validation

Validate before calling

if len(ct) != mlkem1024.CiphertextSize1024 {
    return fmt.Errorf("ciphertext len %d != %d", len(ct), mlkem1024.CiphertextSize1024)
}

Type guard

func isMLKEM1024Ciphertext(b []byte) bool {
    return len(b) == mlkem1024.CiphertextSize1024
}

Try / catch

shared, err := dk.Decapsulate(ct)
if err != nil {
    return fmt.Errorf("decapsulate failed (ct len=%d): %w", len(ct), err)
}

Prevention

When it happens

Trigger: Passing a 768-size ciphertext to a 1024 decapsulator, a ciphertext with a transport header still attached, a hex string that was not decoded, or a buffer that was sliced to the wrong bound.

Common situations: Cross-parameter-set mix-ups (decapsulator and ciphertext from different ML-KEM variants), network framing not stripped, base64 not decoded, or an off-by-one slice around a ciphertext blob.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/a5e68ca4f27a8dc8. Report an issue: GitHub.