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.

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.

Appendix: 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)