slackhq/nebula · error
key was not 64 bytes, is invalid ed25519 private key
Error message
key was not 64 bytes, is invalid ed25519 private key
What it means
For CA (isCA) certificates on Curve_CURVE25519, the signing key must be a 64-byte ed25519 private key; VerifyPrivateKey rejects any other length before deriving the public key (which would otherwise panic on a slice bounds error). This error means the supplied key bytes have the wrong length for an ed25519 private key.
Source
Thrown at cert/cert_v1.go:144
default:
return false
}
}
func (c *certificateV1) Expired(t time.Time) bool {
return c.details.notBefore.After(t) || c.details.notAfter.Before(t)
}
func (c *certificateV1) VerifyPrivateKey(curve Curve, key []byte) error {
if curve != c.details.curve {
return fmt.Errorf("curve in cert and private key supplied don't match")
}
if c.details.isCA {
switch curve {
case Curve_CURVE25519:
// the call to PublicKey below will panic slice bounds out of range otherwise
if len(key) != ed25519.PrivateKeySize {
return fmt.Errorf("key was not 64 bytes, is invalid ed25519 private key")
}
if !ed25519.PublicKey(c.details.publicKey).Equal(ed25519.PrivateKey(key).Public()) {
return fmt.Errorf("public key in cert and private key supplied don't match")
}
case Curve_P256:
privkey, err := ecdh.P256().NewPrivateKey(key)
if err != nil {
return fmt.Errorf("cannot parse private key as P256: %w", err)
}
pub := privkey.PublicKey().Bytes()
if !bytes.Equal(pub, c.details.publicKey) {
return fmt.Errorf("public key in cert and private key supplied don't match")
}
default:
return fmt.Errorf("invalid curve: %s", curve)
}
return nilView on GitHub (pinned to dd8f660c0a)
Solutions
- Supply the full 64-byte ed25519 private key (seed + public half); if you only have a 32-byte seed, expand it with ed25519.NewKeyFromSeed
- Verify you are not passing a P256/private key of the wrong algorithm
- Check the key file was loaded completely (no truncation, correct decoding)
Example fix
// before seed := make([]byte, 32) rand.Read(seed) err := caCert.VerifyPrivateKey(cert.Curve_CURVE25519, seed) // 32 bytes: error // after key := ed25519.NewKeyFromSeed(seed) // full 64-byte private key err := caCert.VerifyPrivateKey(cert.Curve_CURVE25519, key)
Defensive patterns
Strategy: validation
Validate before calling
if cert.Curve() == cert.Curve_CURVE25519 && len(key) != ed25519.PrivateKeySize {
return fmt.Errorf("need full 64-byte ed25519 private key, got %d bytes", len(key))
}
err := cert.VerifyPrivateKey(cert.Curve(), key) Prevention
- Store and load the full 64-byte ed25519 private key, not the 32-byte seed
- Expand seeds with ed25519.NewKeyFromSeed before use
- Check key file lengths after decode to catch truncation
- Never reuse the same key blob across curve types
When it happens
Trigger: Calling VerifyPrivateKey(Curve_CURVE25519, key) on a certificateV1 where c.details.isCA is true and len(key) != ed25519.PrivateKeySize (64).
Common situations: Passing a 32-byte ed25519 seed instead of the full 64-byte private key; passing a P256 key to a Curve25519 CA cert; reading a PEM/der key file that was truncated or in a different format.
Related errors
- curve in cert and private key supplied don't match
- public key in cert and private key supplied don't match
- key was not %d bytes, is invalid ed25519 private key
- key was not %d bytes, is invalid %s private key
- key was not %d bytes, is invalid Ed25519 private key
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/4314143beaa74a62.
Report an issue: GitHub.