golang/go · error
ed25519: bad public key length: {l}
Error message
ed25519: bad public key length: {l} What it means
Returned by NewPublicKey when pubBytes is not exactly publicKeySize (32) bytes. Ed25519 public keys are the y-coordinate plus a sign bit packed into 32 bytes per RFC 8032.
Source
Thrown at src/crypto/internal/fips140/ed25519/ed25519.go:143
}
// Note that we are not decompressing the public key point here,
// because it takes > 20% of the time of a signature generation.
// Signing doesn't use it as a point anyway.
copy(priv.pub[:], privBytes[32:])
copy(priv.prefix[:], h[32:])
return priv, nil
}
func NewPublicKey(pub []byte) (*PublicKey, error) {
p := &PublicKey{}
return newPublicKey(p, pub)
}
func newPublicKey(pub *PublicKey, pubBytes []byte) (*PublicKey, error) {
if l := len(pubBytes); l != publicKeySize {
return nil, errors.New("ed25519: bad public key length: " + strconv.Itoa(l))
}
// SetBytes checks that the point is on the curve.
if _, err := pub.a.SetBytes(pubBytes); err != nil {
return nil, errors.New("ed25519: bad public key")
}
copy(pub.aBytes[:], pubBytes)
return pub, nil
}
// Domain separation prefixes used to disambiguate Ed25519/Ed25519ph/Ed25519ctx.
// See RFC 8032, Section 2 and Section 5.1.
const (
// domPrefixPure is empty for pure Ed25519.
domPrefixPure = ""
// domPrefixPh is dom2(phflag=1) for Ed25519ph. It must be followed by the
// uint8-length prefixed context.
domPrefixPh = "SigEd25519 no Ed25519 collisions\x01"
// domPrefixCtx is dom2(phflag=0) for Ed25519ctx. It must be followed by theView on GitHub (pinned to b6b368adc5)
Solutions
- Supply exactly 32 raw bytes representing the Ed25519 public key.
- Decode hex/base64 before calling and verify length==32.
- Ensure the bytes are from an Ed25519 keypair, not X25519 — they will pass length but may fail the next check (bad public key).
Example fix
// before
pub, err := ed25519.NewPublicKey([]byte(pubHex)) // hex string as bytes
// after
b, err := hex.DecodeString(pubHex)
if err != nil { return err }
if len(b) != 32 { return fmt.Errorf("ed25519 pubkey must be 32 bytes") }
pub, err := ed25519.NewPublicKey(b) Defensive patterns
Strategy: validation
Validate before calling
const ed25519PubSize = 32
if len(b) != ed25519PubSize {
return nil, fmt.Errorf("ed25519 public key must be %d bytes, got %d", ed25519PubSize, len(b))
}
return ed25519.NewPublicKey(b) Try / catch
pub, err := ed25519.NewPublicKey(b)
if err != nil {
if strings.Contains(err.Error(), "bad public key length") {
return nil, ErrInvalidPublicKeyEncoding
}
return nil, err
} Prevention
- Reject X25519 public keys at the caller via context (they pass length but fail curve check).
- Decode all hex/base64 keys at the boundary.
- Tag key material with its curve to avoid X25519/Ed25519 mix-ups.
When it happens
Trigger: Calling fips140/ed25519.NewPublicKey(pub) with a slice whose length is not 32 (e.g. 64 bytes that are actually a private key, 33-byte compressed point from another curve, hex string).
Common situations: Passing a hex/base64 string instead of decoded bytes; passing a 64-byte private key where only the public key was expected; confusing an X25519 (Curve25519) public key with an Ed25519 one — both are 32 bytes but only the latter decodes.
Related errors
- ed25519: bad seed length: {l}
- ed25519: bad private key length: {l}
- ed25519: bad Ed25519ph message hash length: {l}
- ed25519: bad Ed25519ph context length: {l}
- ed25519: bad Ed25519ctx context length: {l}
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/f81da6a9b7b955fa.
Report an issue: GitHub.