golang/go · error

ed25519: bad signature length: {l}

Error message

ed25519: bad signature length: {l}

What it means

Returned by verifyWithDom when the signature slice is not exactly signatureSize (64) bytes — a 32-byte R followed by a 32-byte S, per RFC 8032. Apply to Sign/SignPH/SignCtx verification paths and to pure Verify.

Source

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

	if l := len(context); l > 255 {
		return errors.New("ed25519: bad Ed25519ph context length: " + strconv.Itoa(l))
	}
	return verifyWithDom(pub, message, sig, domPrefixPh, context)
}

func VerifyCtx(pub *PublicKey, message []byte, sig []byte, context string) error {
	fipsSelfTest()
	// FIPS 186-5 specifies Ed25519 and Ed25519ph (with context), but not Ed25519ctx.
	fips140.RecordNonApproved()
	if l := len(context); l > 255 {
		return errors.New("ed25519: bad Ed25519ctx context length: " + strconv.Itoa(l))
	}
	return verifyWithDom(pub, message, sig, domPrefixCtx, context)
}

func verifyWithDom(pub *PublicKey, message, sig []byte, domPrefix, context string) error {
	if l := len(sig); l != signatureSize {
		return errors.New("ed25519: bad signature length: " + strconv.Itoa(l))
	}

	if sig[63]&224 != 0 {
		return errors.New("ed25519: invalid signature")
	}

	kh := sha512.New()
	if domPrefix != domPrefixPure {
		kh.Write([]byte(domPrefix))
		kh.Write([]byte{byte(len(context))})
		kh.Write([]byte(context))
	}
	kh.Write(sig[:32])
	kh.Write(pub.aBytes[:])
	kh.Write(message)
	hramDigest := make([]byte, 0, sha512Size)
	hramDigest = kh.Sum(hramDigest)
	k, err := edwards25519.NewScalar().SetUniformBytes(hramDigest)

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Pass exactly 64 raw bytes for the signature.
  2. Decode hex/base64 first and assert length==64.
  3. If you received a DER signature, you are on the wrong algorithm — Ed25519 uses raw concatenation, not DER.

Example fix

// before
ok := ed25519.Verify(pub, msg, []byte(sigHex))

// after
b, err := hex.DecodeString(sigHex)
if err != nil { return err }
if len(b) != 64 { return fmt.Errorf("ed25519 sig must be 64 bytes") }
err = ed25519.Verify(pub, msg, b)
Defensive patterns

Strategy: validation

Validate before calling

const ed25519SigSize = 64
if len(sig) != ed25519SigSize {
    return fmt.Errorf("ed25519 signature must be %d bytes, got %d", ed25519SigSize, len(sig))
}
return ed25519.Verify(pub, message, sig)

Try / catch

if err := ed25519.Verify(pub, message, sig); err != nil {
    if strings.Contains(err.Error(), "bad signature length") {
        return fmt.Errorf("received %d-byte sig; expected raw 64-byte Ed25519, not DER", len(sig))
    }
    return err
}

Prevention

When it happens

Trigger: Calling Verify / VerifyPH / VerifyCtx with sig of length != 64 — e.g. DER-encoded signature, 96-byte concatenated form, truncated bytes, hex string.

Common situations: Passing an ASN.1 DER ECDSA-style signature to Ed25519 verify; passing hex/base64 strings instead of decoded bytes; truncation in transit; off-by-one slice handling.

Related errors


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