golang/go · error

ecdsa: curve not supported by PublicKey.Bytes

Error message

ecdsa: curve not supported by PublicKey.Bytes

What it means

Thrown by PublicKey.Bytes() when pub.Curve does not match any of P224, P256, P384, or P521 in the switch statement. The serialization to uncompressed SEC 1 format is only implemented for standard NIST curves via the internal FIPS ecdsa package.

Source

Thrown at src/crypto/ecdsa/ecdsa.go:155

// PublicKey.Curve must be one of [elliptic.P224], [elliptic.P256],
// [elliptic.P384], or [elliptic.P521], or Bytes returns an error.
//
// Bytes returns the same format as [ecdh.PublicKey.Bytes] does for NIST curves.
//
// Note that public keys are more commonly encoded in DER (or PEM) format, which
// can be generated with [crypto/x509.MarshalPKIXPublicKey] (and [encoding/pem]).
func (pub *PublicKey) Bytes() ([]byte, error) {
	switch pub.Curve {
	case elliptic.P224():
		return publicKeyBytes(ecdsa.P224(), pub)
	case elliptic.P256():
		return publicKeyBytes(ecdsa.P256(), pub)
	case elliptic.P384():
		return publicKeyBytes(ecdsa.P384(), pub)
	case elliptic.P521():
		return publicKeyBytes(ecdsa.P521(), pub)
	default:
		return nil, errors.New("ecdsa: curve not supported by PublicKey.Bytes")
	}
}

func publicKeyBytes[P ecdsa.Point[P]](c *ecdsa.Curve[P], pub *PublicKey) ([]byte, error) {
	k, err := publicKeyToFIPS(c, pub)
	if err != nil {
		return nil, err
	}
	return k.Bytes(), nil
}

// PrivateKey represents an ECDSA private key.
type PrivateKey struct {
	PublicKey

	// D is the private scalar value.
	//
	// Deprecated: modifying the raw value can produce invalid keys, and may

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Ensure the PublicKey was created with a standard NIST curve (P224/P256/P384/P521) — validate at construction time.
  2. If using a custom curve, implement your own serialization using the X and Y big.Int fields directly.
  3. Check pub.Curve against the standard singletons before calling Bytes() and handle the unsupported case explicitly.

Example fix

// before
b, err := pub.Bytes()

// after
switch pub.Curve {
case elliptic.P224(), elliptic.P256(), elliptic.P384(), elliptic.P521():
    b, err = pub.Bytes()
default:
    // manual serialization for non-NIST curves
    b = append([]byte{0x04}, append(pub.X.FillBytes(make([]byte, pub.Curve.Params().BitSize/8)), pub.Y.FillBytes(make([]byte, pub.Curve.Params().BitSize/8))...)
}
Defensive patterns

Strategy: validation

Validate before calling

func canSerializePublicKey(pub *ecdsa.PublicKey) bool {
    switch pub.Curve {
    case elliptic.P224(), elliptic.P256(), elliptic.P384(), elliptic.P521():
        return true
    }
    return false
}

Try / catch

b, err := pub.Bytes()
if err != nil {
    // fall back to manual serialization using pub.X, pub.Y
    fieldSize := (pub.Curve.Params().BitLen + 7) / 8
    b = append([]byte{0x04}, append(pub.X.FillBytes(make([]byte, fieldSize)), pub.Y.FillBytes(make([]byte, fieldSize))...)...)
}

Prevention

When it happens

Trigger: Calling Bytes() on a PublicKey where Curve is a custom or non-standard elliptic.Curve. This can also occur if the curve was set to the Params() value or a third-party curve type that doesn't match the singletons.

Common situations: Loading keys from external sources that specify non-standard curves; programmatically constructing a PublicKey with a custom curve; deserialization code that doesn't validate the curve before calling Bytes().

Related errors


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