golang/go · error
invalid P256 compressed point encoding
Error message
invalid P256 compressed point encoding
What it means
Concrete P-256 instance of the generated compressed-point error (generate.go:223 expanded into p256.go:96). Thrown when decompressing a SEC1 compressed P-256 point (type byte 0x02/0x03, length 1+32) whose x-coordinate yields no valid y (x^3-3x+b not a quadratic residue mod the P-256 prime).
Source
Thrown at src/crypto/internal/fips140/nistec/p256.go:96
if err := p256CheckOnCurve(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) == p256CompressedLength && (b[0] == 2 || b[0] == 3):
x, err := new(fiat.P256Element).SetBytes(b[1:])
if err != nil {
return nil, err
}
// y² = x³ - 3x + b
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")
}
}View on GitHub (pinned to b6b368adc5)
Solutions
- Reject malformed compressed P-256 points from untrusted sources with explicit error handling.
- Verify len(b) == 33 and b[0] in {2,3} before calling SetBytes.
- Re-serialize the point from a known-good P-256 point via BytesCompressed and compare.
- If decompressing from raw x, prefer the curve's own SetBytes to apply the constant-time validation.
Example fix
// before
p, err := nistec.NewP256Point().SetBytes(b) // b corrupted
// after
if len(b) != 33 || (b[0] != 2 && b[0] != 3) {
return errors.New("not a compressed P-256 point")
}
p, err := nistec.NewP256Point().SetBytes(b)
if err != nil { return fmt.Errorf("off-curve: %w", err) } Defensive patterns
Strategy: validation
Validate before calling
// Validate compressed P-256 shape before SetBytes.
if len(b) != 33 || (b[0] != 2 && b[0] != 3) {
return errors.New("not a compressed P-256 point")
} Type guard
func isCompressedP256(b []byte) bool {
return len(b) == 33 && (b[0] == 2 || b[0] == 3)
} Try / catch
p, err := nistec.NewP256Point().SetBytes(b)
if err != nil {
return fmt.Errorf("P-256 decompression failed (len=%d): %w", len(b), err)
} Prevention
- Reject malformed compressed P-256 points from untrusted peers explicitly.
- Verify length and prefix byte before calling SetBytes.
- Re-encode from a known-good point and diff suspect inputs.
When it happens
Trigger: Compressed P-256 point whose x is off-curve, an x byte-swapped or end-flipped, or a compressed encoding sized for a different curve passed to the P-256 parser.
Common situations: Fuzzed/adversarial public keys, cross-curve mix-ups, transit corruption, or a copy-paste of a P-384 compressed point.
Related errors
- invalid P256 point encoding
- invalid {{.P}} compressed point encoding
- invalid {{.P}} point encoding
- P256 point not on curve
- invalid {{ .Element }} encoding
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/4e8d382fd8b35705.
Report an issue: GitHub.