golang/go · error
ed25519: bad public key
Error message
ed25519: bad public key
What it means
Returned by NewPublicKey after SetBytes fails — the 32 bytes decoded to a point that is not on the Ed25519 curve (or is one of the excluded low-order points). Length is correct but the bytes do not represent a valid group element.
Source
Thrown at src/crypto/internal/fips140/ed25519/ed25519.go:147
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 the
// uint8-length prefixed context.
domPrefixCtx = "SigEd25519 no Ed25519 collisions\x00"
)
View on GitHub (pinned to b6b368adc5)
Solutions
- Confirm the bytes were produced by an Ed25519 key generation, not X25519 or another curve.
- Re-fetch the public key from the authoritative source to rule out corruption.
- Surface the error to the user as 'untrusted public key is malformed' — do not fall back to a default key.
Defensive patterns
Strategy: try-catch
Try / catch
pub, err := ed25519.NewPublicKey(b)
if err != nil {
if strings.Contains(err.Error(), "bad public key") && !strings.Contains(err.Error(), "length") {
// length OK but point off-curve
return nil, ErrKeyNotOnCurve
}
return nil, err
} Prevention
- Treat off-curve public keys as adversarial — never fall back to a default.
- Distinguish X25519 (ECDH) from Ed25519 (signing) at the type/import layer.
- Verify key origin before import.
When it happens
Trigger: Calling NewPublicKey with 32 bytes that are random, corrupted, or a valid 32-byte blob from a different curve (e.g. X25519 public key, or an Ed448-truncated key).
Common situations: Mixing up X25519 (ECDH) and Ed25519 (signing) public keys — both 32 bytes; corrupted key material from storage/network; feeding an identity element that the encoding explicitly rejects; typos in pasted keys.
Related errors
- ed25519: bad seed length: {l}
- ed25519: bad private key length: {l}
- ed25519: bad public key length: {l}
- ed25519: bad Ed25519ph message hash length: {l}
- ed25519: bad Ed25519ph context length: {l}
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/27274a574ec53c40.
Report an issue: GitHub.