golang/go · error

ecdsa: invalid uncompressed public key

Error message

ecdsa: invalid uncompressed public key

What it means

Thrown by ecdsa.ParseUncompressedPublicKey when the input data is empty or its first byte is not 0x04. Per SEC 1 section 2.3.3, uncompressed elliptic curve points are encoded as 0x04 followed by the x and y coordinates. Any other prefix (0x02/0x03 for compressed, 0x00 for point at infinity) or missing data is rejected.

Source

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

}

// ParseUncompressedPublicKey parses a public key encoded as an uncompressed
// point according to SEC 1, Version 2.0, Section 2.3.3 (also known as the X9.62
// uncompressed format). It returns an error if the point is not in uncompressed
// form, is not on the curve, or is the point at infinity.
//
// curve must be one of [elliptic.P224], [elliptic.P256], [elliptic.P384], or
// [elliptic.P521], or ParseUncompressedPublicKey returns an error.
//
// ParseUncompressedPublicKey accepts the same format as
// [ecdh.Curve.NewPublicKey] does for NIST curves, but returns a [PublicKey]
// instead of an [ecdh.PublicKey].
//
// Note that public keys are more commonly encoded in DER (or PEM) format, which
// can be parsed with [crypto/x509.ParsePKIXPublicKey] (and [encoding/pem]).
func ParseUncompressedPublicKey(curve elliptic.Curve, data []byte) (*PublicKey, error) {
	if len(data) < 1 || data[0] != 4 {
		return nil, errors.New("ecdsa: invalid uncompressed public key")
	}
	switch curve {
	case elliptic.P224():
		return parseUncompressedPublicKey(ecdsa.P224(), curve, data)
	case elliptic.P256():
		return parseUncompressedPublicKey(ecdsa.P256(), curve, data)
	case elliptic.P384():
		return parseUncompressedPublicKey(ecdsa.P384(), curve, data)
	case elliptic.P521():
		return parseUncompressedPublicKey(ecdsa.P521(), curve, data)
	default:
		return nil, errors.New("ecdsa: curve not supported by ParseUncompressedPublicKey")
	}
}

func parseUncompressedPublicKey[P ecdsa.Point[P]](c *ecdsa.Curve[P], curve elliptic.Curve, data []byte) (*PublicKey, error) {
	k, err := ecdsa.NewPublicKey(c, data)
	if err != nil {

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Ensure data[0] == 0x04 and that the total length is 1 + 2*fieldSizeBytes (e.g., 65 bytes for P-256).
  2. If the key is DER/PEM encoded, use crypto/x509.ParsePKIXPublicKey instead of ParseUncompressedPublicKey.
  3. If the key is compressed (prefix 0x02/0x03), decompress it first or use a function that handles compressed points.

Example fix

// before
pub, err := ecdsa.ParseUncompressedPublicKey(elliptic.P256(), derBytes)

// after
// for raw uncompressed point:
pub, err := ecdsa.ParseUncompressedPublicKey(elliptic.P256(), rawPointBytes) // rawPointBytes[0] == 0x04
// for DER/PEM:
// block, _ := pem.Decode(pemBytes)
// pubAny, err := x509.ParsePKIXPublicKey(block.Bytes)
Defensive patterns

Strategy: validation

Validate before calling

func validateUncompressedPoint(data []byte, curve elliptic.Curve) error {
    if len(data) < 1 || data[0] != 0x04 {
        return errors.New("expected uncompressed point (prefix 0x04)")
    }
    expectedLen := 1 + 2*((curve.Params().BitLen+7)/8)
    if len(data) != expectedLen {
        return fmt.Errorf("expected %d bytes, got %d", expectedLen, len(data))
    }
    return nil
}

Type guard

func isUncompressedPoint(data []byte) bool {
    return len(data) >= 1 && data[0] == 0x04
}

Try / catch

pub, err := ecdsa.ParseUncompressedPublicKey(curve, data)
if err != nil {
    return fmt.Errorf("not a valid uncompressed point (prefix=0x%02x): %w", data[0], err)
}

Prevention

When it happens

Trigger: Calling ParseUncompressedPublicKey(curve, data) where data is empty, nil, or starts with a byte other than 0x04. Common cases: passing a compressed point (prefix 0x02 or 0x03), passing a DER/ASN.1 encoded SubjectPublicKeyInfo, or passing raw coordinate bytes without the 0x04 prefix.

Common situations: Receiving a compressed public key from a protocol that uses point compression and trying to parse it as uncompressed; loading a key from a DER-encoded certificate (which wraps the point in ASN.1 structures) without first using x509.ParsePKIXPublicKey; building the point bytes manually and forgetting the 0x04 header.

Related errors


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