golang/go · error

ecdsa: unsupported curve by crypto/ecdh

Error message

ecdsa: unsupported curve by crypto/ecdh

What it means

Thrown by ecdsa.PublicKey.ECDH() when curveToECDH(pub.Curve) returns nil. The curveToECDH function only maps elliptic.P256, elliptic.P384, and elliptic.P521 to their ecdh equivalents — elliptic.P224 and any custom curve return nil, triggering this error. ECDSA keys on unsupported curves cannot be converted to ecdh.PublicKey for key agreement.

Source

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

	// invalidate internal optimizations; moreover, [big.Int] methods are not
	// suitable for operating on cryptographic values. To encode and decode
	// PublicKey values, use [PublicKey.Bytes] and [ParseUncompressedPublicKey]
	// or [crypto/x509.MarshalPKIXPublicKey] and [crypto/x509.ParsePKIXPublicKey].
	// For ECDH, use [crypto/ecdh]. For lower-level elliptic curve operations,
	// use a third-party module like filippo.io/nistec.
	X, Y *big.Int
}

// Any methods implemented on PublicKey might need to also be implemented on
// PrivateKey, as the latter embeds the former and will expose its methods.

// ECDH returns k as a [ecdh.PublicKey]. It returns an error if the key is
// invalid according to the definition of [ecdh.Curve.NewPublicKey], or if the
// Curve is not supported by crypto/ecdh.
func (pub *PublicKey) ECDH() (*ecdh.PublicKey, error) {
	c := curveToECDH(pub.Curve)
	if c == nil {
		return nil, errors.New("ecdsa: unsupported curve by crypto/ecdh")
	}
	k, err := pub.Bytes()
	if err != nil {
		return nil, err
	}
	return c.NewPublicKey(k)
}

// Equal reports whether pub and x have the same value.
//
// Two keys are only considered to have the same value if they have the same Curve value.
// Note that for example [elliptic.P256] and elliptic.P256().Params() are different
// values, as the latter is a generic not constant time implementation.
func (pub *PublicKey) Equal(x crypto.PublicKey) bool {
	xx, ok := x.(*PublicKey)
	if !ok {
		return false
	}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Check pub.Curve against elliptic.P256(), elliptic.P384(), or elliptic.P521() before calling ECDH(); for P-224, use a separate ECDH key pair on a supported curve.
  2. Generate a dedicated ecdh.PrivateKey with ecdh.P256().GenerateKey() (or P384/P521) for key agreement instead of reusing an ECDSA key.
  3. If you need P-224 key agreement, use an alternative ECDH implementation since crypto/ecdh does not support it.

Example fix

// before
ecdhPub, err := ecdsaPub.ECDH()

// after
switch ecdsaPub.Curve {
case elliptic.P256(), elliptic.P384(), elliptic.P521():
    ecdhPub, err = ecdsaPub.ECDH()
default:
    return fmt.Errorf("curve %s not supported for ECDH", ecdsaPub.Curve.Params().Name)
}
Defensive patterns

Strategy: validation

Validate before calling

func isECDSACurveECDHCompatible(c elliptic.Curve) bool {
    switch c {
    case elliptic.P256(), elliptic.P384(), elliptic.P521():
        return true
    }
    return false
}
// call before: pub.ECDH()

Type guard

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

Try / catch

ecdhPub, err := pub.ECDH()
if err != nil {
    return fmt.Errorf("cannot use curve %s for ECDH: %w", pub.Curve.Params().Name, err)
}

Prevention

When it happens

Trigger: Calling ECDH() on an ecdsa.PublicKey whose Curve is elliptic.P224() or a non-standard/custom elliptic.Curve. The method attempts to find a matching crypto/ecdh curve and fails because only P-256, P-384, and P-521 have ecdh.Curve counterparts.

Common situations: Loading a P-224 ECDSA certificate (used in some legacy systems or constrained environments) and trying to derive an ECDH shared secret from its public key; using a custom curve implementation; code that generically converts any ECDSA key to ECDH without checking the curve.

Related errors


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