golang/go · error

ed25519: bad Ed25519ctx context length: {l}

Error message

ed25519: bad Ed25519ctx context length: {l}

What it means

Returned by SignCtx (Ed25519ctx) when the context string exceeds 255 bytes. RFC 8032 limits context to 255 bytes for both Ed25519ctx and Ed25519ph. Also note FIPS 186-5 marks Ed25519ctx as non-approved (RecordNonApproved is called).

Source

Thrown at src/crypto/internal/fips140/ed25519/ed25519.go:211

		return nil, errors.New("ed25519: bad Ed25519ph context length: " + strconv.Itoa(l))
	}
	return signWithDom(signature, priv, message, domPrefixPh, context), nil
}

func SignCtx(priv *PrivateKey, message []byte, context string) ([]byte, error) {
	// Outline the function body so that the returned signature can be
	// stack-allocated.
	signature := make([]byte, signatureSize)
	return signCtx(signature, priv, message, context)
}

func signCtx(signature []byte, priv *PrivateKey, message []byte, context string) ([]byte, error) {
	fipsSelfTest()
	// FIPS 186-5 specifies Ed25519 and Ed25519ph (with context), but not Ed25519ctx.
	fips140.RecordNonApproved()
	// Note that per RFC 8032, Section 5.1, the context SHOULD NOT be empty.
	if l := len(context); l > 255 {
		return nil, errors.New("ed25519: bad Ed25519ctx context length: " + strconv.Itoa(l))
	}
	return signWithDom(signature, priv, message, domPrefixCtx, context), nil
}

func signWithDom(signature []byte, priv *PrivateKey, message []byte, domPrefix, context string) []byte {
	mh := sha512.New()
	if domPrefix != domPrefixPure {
		mh.Write([]byte(domPrefix))
		mh.Write([]byte{byte(len(context))})
		mh.Write([]byte(context))
	}
	mh.Write(priv.prefix[:])
	mh.Write(message)
	messageDigest := make([]byte, 0, sha512Size)
	messageDigest = mh.Sum(messageDigest)
	r, err := edwards25519.NewScalar().SetUniformBytes(messageDigest)
	if err != nil {
		panic("ed25519: internal error: setting scalar failed")

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Reduce context to <= 255 bytes; prefer a short identifier.
  2. For FIPS-approved signing with context, use SignPH (Ed25519ph) instead of SignCtx.
  3. Hash long context material down to 32 bytes before passing.

Example fix

// before
sig, err := ed25519.SignCtx(priv, msg, veryLongCtx)

// after
ctxHash := sha256.Sum256([]byte(veryLongCtx))
sig, err := ed25519.SignCtx(priv, msg, string(ctxHash[:]))
Defensive patterns

Strategy: validation

Validate before calling

if len(context) > 255 {
    h := sha256.Sum256([]byte(context))
    context = string(h[:])
}
sig, err := ed25519.SignCtx(priv, message, context)

Try / catch

sig, err := ed25519.SignCtx(priv, message, context)
if err != nil {
    if strings.Contains(err.Error(), "bad Ed25519ctx context length") {
        return nil, fmt.Errorf("context too long (%d > 255)", len(context))
    }
    return nil, err
}

Prevention

When it happens

Trigger: Calling fips140/ed25519.SignCtx(priv, message, context) with len(context) > 255.

Common situations: Same as 347 — oversized domain-separation string. Additionally, choosing SignCtx without realizing FIPS mode treats Ed25519ctx as non-approved.

Related errors


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