golang/go · error

mlkemtest: Encapsulate768: random must be 32 bytes

Error message

mlkemtest: Encapsulate768: random must be 32 bytes

What it means

Returned by mlkemtest.Encapsulate768 (a known-answer-test helper exposing ML-KEM.Encaps_internal) when the randomness slice is not exactly 32 bytes. FIPS 203 derandomized encapsulation requires a 32-byte seed (the 'z' input); any other length is a programmer error. The function is intended only for KAT testing, not production use.

Source

Thrown at src/crypto/mlkem/mlkemtest/mlkemtest.go:22

// Package mlkemtest provides testing functions for the ML-KEM algorithm.
package mlkemtest

import (
	fips140mlkem "crypto/internal/fips140/mlkem"
	"crypto/internal/fips140only"
	"crypto/mlkem"
	"errors"
)

// Encapsulate768 implements derandomized ML-KEM-768 encapsulation
// (ML-KEM.Encaps_internal from FIPS 203) using the provided encapsulation key
// ek and 32 bytes of randomness.
//
// It must only be used for known-answer tests.
func Encapsulate768(ek *mlkem.EncapsulationKey768, random []byte) (sharedKey, ciphertext []byte, err error) {
	if len(random) != 32 {
		return nil, nil, errors.New("mlkemtest: Encapsulate768: random must be 32 bytes")
	}
	if fips140only.Enforced() {
		return nil, nil, errors.New("crypto/mlkem/mlkemtest: use of derandomized encapsulation is not allowed in FIPS 140-only mode")
	}
	k, err := fips140mlkem.NewEncapsulationKey768(ek.Bytes())
	if err != nil {
		return nil, nil, errors.New("mlkemtest: Encapsulate768: failed to reconstruct key: " + err.Error())
	}
	sharedKey, ciphertext = k.EncapsulateInternal((*[32]byte)(random))
	return sharedKey, ciphertext, nil
}

// Encapsulate1024 implements derandomized ML-KEM-1024 encapsulation
// (ML-KEM.Encaps_internal from FIPS 203) using the provided encapsulation key
// ek and 32 bytes of randomness.
//
// It must only be used for known-answer tests.
func Encapsulate1024(ek *mlkem.EncapsulationKey1024, random []byte) (sharedKey, ciphertext []byte, err error) {

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Provide exactly 32 bytes: random := make([]byte, 32); crypto/rand.Read(random).
  2. If you have a fixed-size source, copy 32 bytes: var z [32]byte; ... Encapsulate768(ek, z[:]).
  3. For production, use the standard (randomized) Encapsulate API on mlkem.EncapsulationKey768 instead of the test helper.

Example fix

// before
z := make([]byte, 16)
rand.Read(z)
shared, ct, err := mlkemtest.Encapsulate768(ek, z) // error

// after
z := make([]byte, 32)
rand.Read(z)
shared, ct, err := mlkemtest.Encapsulate768(ek, z)
Defensive patterns

Strategy: validation

Validate before calling

if len(random) != 32 {
    return nil, nil, fmt.Errorf("random must be 32 bytes, got %d", len(random))
}
return mlkemtest.Encapsulate768(ek, random)

Type guard

func isValidSeed(b []byte) bool { return len(b) == 32 }

Try / catch

shared, ct, err := mlkemtest.Encapsulate768(ek, random)
if err != nil && strings.Contains(err.Error(), "random must be 32 bytes") {
    random = make([]byte, 32)
    rand.Read(random)
    shared, ct, err = mlkemtest.Encapsulate768(ek, random)
}
return shared, ct, err

Prevention

When it happens

Trigger: Calling Encapsulate768(ek, random) with a slice of length other than 32. Passing a 16-byte or 64-byte buffer by mistake. Reusing an RNG that returns variable-length output.

Common situations: Adapting test code that generated 16 bytes (e.g., for older schemes) to ML-KEM. Passing crypto/rand.Read output without sizing it. Confusing the 32-byte encapsulation seed with the 32-byte shared-secret length.

Related errors


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