golang/go · error

invalid P256 point encoding

Error message

invalid P256 point encoding

What it means

Concrete P-256 instance of the generated point-encoding error (generate.go:239 expanded into p256.go:112). Thrown when SetBytes on a P-256 point falls through all recognized cases: 0x04 uncompressed of length 65, 0x02/0x03 compressed of length 33, or 0x00 infinity. Any other leading byte or length is rejected.

Source

Thrown at src/crypto/internal/fips140/nistec/p256.go:112

		y := p256Polynomial(new(fiat.P256Element), x)
		if !p256Sqrt(y, y) {
			return nil, errors.New("invalid P256 compressed point encoding")
		}

		// Select the positive or negative root, as indicated by the least
		// significant bit, based on the encoding type byte.
		otherRoot := new(fiat.P256Element)
		otherRoot.Sub(otherRoot, y)
		cond := y.Bytes()[p256ElementLength-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 P256 point encoding")
	}
}

var _p256B *fiat.P256Element
var _p256BOnce sync.Once

func p256B() *fiat.P256Element {
	_p256BOnce.Do(func() {
		_p256B, _ = new(fiat.P256Element).SetBytes([]byte{0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd, 0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x6, 0xb0, 0xcc, 0x53, 0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b})
	})
	return _p256B
}

// p256Polynomial sets y2 to x³ - 3x + b, and returns y2.
func p256Polynomial(y2, x *fiat.P256Element) *fiat.P256Element {
	y2.Square(x)
	y2.Mul(y2, x)

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Wrap raw (x,y) as 0x04 || x || y (65 bytes for P-256) before SetBytes.
  2. Decode hex/base64 to raw bytes first.
  3. Convert hybrid (0x06/0x07) to uncompressed 0x04 if the source emits it.
  4. Strip any length prefix or envelope the P-256 parser does not expect.

Example fix

// before
p, err := nistec.NewP256Point().SetBytes(rawXY) // missing 0x04
// after
buf := make([]byte, 65)
buf[0] = 4
copy(buf[1:33], x); copy(buf[33:], y)
p, err := nistec.NewP256Point().SetBytes(buf)
Defensive patterns

Strategy: validation

Validate before calling

// Wrap raw P-256 coordinates as 0x04 || x || y.
buf := make([]byte, 65)
buf[0] = 4
copy(buf[1:33], x)
copy(buf[33:], y)

Type guard

func isSEC1P256(b []byte) bool {
    switch {
    case len(b) == 1 && b[0] == 0: return true
    case len(b) == 65 && b[0] == 4: return true
    case len(b) == 33 && (b[0] == 2 || b[0] == 3): return true
    }
    return false
}

Try / catch

p, err := nistec.NewP256Point().SetBytes(b)
if err != nil {
    return fmt.Errorf("unrecognized P-256 encoding (prefix=0x%x, len=%d): %w", b[0], len(b), err)
}

Prevention

When it happens

Trigger: Input with an unrecognized prefix (0x06/0x07 hybrid, 0x01), wrong-length buffer, raw x||y without the 0x04 prefix, or an un-decoded hex/base64 string.

Common situations: Hybrid SEC1 (unsupported), dropped length prefix, JWK/COSE coordinate arrays mistaken for SEC1, or a byte slice that included extra framing.

Related errors


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