golang/go · error

invalid {{.P}} compressed point encoding

Error message

invalid {{.P}} compressed point encoding

What it means

Generated into each NIST curve from generate.go:223. Thrown when parsing a compressed SEC1 point (type byte 0x02/0x03, length 1+ElementLength) where the x-coordinate yields no valid y, i.e. x^3-3x+b is not a quadratic residue. The point is not on the curve.

Source

Thrown at src/crypto/internal/fips140/nistec/generate.go:223

		if err := {{.p}}CheckOnCurve(x, y); err != nil {
			return nil, err
		}
		p.x.Set(x)
		p.y.Set(y)
		p.z.One()
		return p, nil

	// Compressed form.
	case len(b) == 1+{{.p}}ElementLength && (b[0] == 2 || b[0] == 3):
		x, err := new({{.Element}}).SetBytes(b[1:])
		if err != nil {
			return nil, err
		}

		// y² = x³ - 3x + b
		y := {{.p}}Polynomial(new({{.Element}}), x)
		if !{{.p}}Sqrt(y, y) {
			return nil, errors.New("invalid {{.P}} compressed point encoding")
		}

		// Select the positive or negative root, as indicated by the least
		// significant bit, based on the encoding type byte.
		otherRoot := new({{.Element}})
		otherRoot.Sub(otherRoot, y)
		cond := y.Bytes()[{{.p}}ElementLength-1]&1 ^ b[0]&1
		y.Select(otherRoot, y, int(cond))

		p.x.Set(x)
		p.y.Set(y)
		p.z.One()
		return p, nil

	default:
		return nil, errors.New("invalid {{.P}} point encoding")
	}
}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Validate the source of the point; reject compressed points from untrusted peers with explicit error handling.
  2. Confirm the type byte (0x02/0x03) and length match the target curve (1+ElementLength).
  3. Use the curve-specific point parser rather than re-implementing decompression.
  4. Re-serialize the point via BytesCompressed from a known-good point and diff against the input.

Example fix

// before
p, err := nistec.NewP256Point().SetBytes(b) // b is a corrupted compressed point
// after
if !(len(b) == 1+p256ElementLength && (b[0] == 2 || b[0] == 3)) {
    return errors.New("not a P-256 compressed point")
}
p, err := nistec.NewP256Point().SetBytes(b)
if err != nil { return fmt.Errorf("point off curve: %w", err) }
Defensive patterns

Strategy: validation

Validate before calling

// Validate SEC1 compressed shape before decompression.
if len(b) != 1+elementLength || (b[0] != 2 && b[0] != 3) {
    return errors.New("not a compressed point")
}

Type guard

func isCompressedSEC1(b []byte, elLen int) bool {
    return len(b) == 1+elLen && (b[0] == 2 || b[0] == 3)
}

Try / catch

p, err := curve.NewPoint().SetBytes(b)
if err != nil {
    return fmt.Errorf("point decompression failed (len=%d): %w", len(b), err)
}

Prevention

When it happens

Trigger: Compressed point with an x that is not on the curve, an x that was corrupted/truncated, or a compressed encoding from a different curve (e.g. P-384 point fed to a P-256 parser).

Common situations: Fuzzed/adversarial public keys, byte-swap or endian errors, cross-curve confusion, or a stale encoding from a draft curve parameter.

Related errors


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