golang/go · error

mldsa: context too long

Error message

mldsa: context too long

What it means

ML-DSA binds an optional context string into the signed message digest (the ctx in FIPS 204's M' construction). The standard caps this context at 255 bytes so it fits in a single length-prefixed byte. computeMessageHash enforces the cap on behalf of both Sign and Verify; anything longer is rejected before any hashing happens. The same context must be supplied to both Sign and Verify or verification will later fail.

Solutions

  1. Cap the context at 255 bytes; if a longer domain separator is needed, hash it down with SHA-256/SHA3-256 and pass the 32-byte digest as the context (the FIPS 204 scheme does not forbid a hash output as ctx).
  2. Validate len(context) <= 255 at the API boundary and surface a clear validation error to the caller.
  3. Keep context a short, stable identifier (application name + version) rather than free-form metadata.

Example fix

// before
sig, err := mldsa.Sign(priv, msg, longDomainString)

// after
if len(context) > 255 {
    sum := sha3.Sum256([]byte(longDomainString))
    context = string(sum[:])
}
sig, err := mldsa.Sign(priv, msg, context)
Defensive patterns

Strategy: validation

Validate before calling

if len(context) > 255 {
    return fmt.Errorf("mldsa context limited to 255 bytes, got %d", len(context))
}

Type guard

func isValidContext(ctx string) bool { return len(ctx) <= 255 }

Prevention

When it happens

Trigger: Calling mldsa.Sign(priv, msg, context) or mldsa.Verify(pub, msg, sig, context) with len(context) > 255.

Common situations: Embedding a long URI, JWT, certificate chain, or concatenated metadata blob as the context; copying a 'domain' string from config without length-checking; logging context that grew over time.

Related errors


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

Appendix: source

Thrown at src/crypto/internal/fips140/mldsa/mldsa.go:332

		return nil, errInvalidPublicKeyLength
	}

	// We don't precompute A and t1Hat here, because they would make the
	// PublicKey over 68KB. Unlike private keys, public keys are often used to
	// verify a signature only once, so precomputation doesn't help as often,
	// but they can stay around in memory, for example as part of a TLS
	// connection's PeerCertificates, so their size is more of a concern.
	// Instead, we compute A and t1Hat on demand in Verify.

	pub.p = p
	copy(pub.raw[:], pk)
	pub.tr = computePublicKeyHash(pk)

	return pub, nil
}

var (
	errContextTooLong    = errors.New("mldsa: context too long")
	errMessageHashLength = errors.New("mldsa: invalid message hash length")
	errRandomLength      = errors.New("mldsa: invalid random length")
)

func Sign(priv *PrivateKey, msg []byte, context string) ([]byte, error) {
	fipsSelfTest()
	fips140.RecordApproved()
	var random [32]byte
	drbg.Read(random[:])
	μ, err := computeMessageHash(priv.pub.tr[:], msg, context)
	if err != nil {
		return nil, err
	}
	return signInternal(priv, &μ, &random), nil
}

func SignDeterministic(priv *PrivateKey, msg []byte, context string) ([]byte, error) {
	fipsSelfTest()

View on GitHub (pinned to b6b368adc5)