golang/go · error
{{.P}} point not on curve
Error message
{{.P}} point not on curve What it means
Generated from generate.go:271. Thrown by {{p}}CheckOnCurve when, for a candidate affine (x,y), y^2 != x^3 - 3x + b. The point fails the curve equation; it is not a valid member of the group.
Source
Thrown at src/crypto/internal/fips140/nistec/generate.go:271
// {{.p}}Polynomial sets y2 to x³ - 3x + b, and returns y2.
func {{.p}}Polynomial(y2, x *{{.Element}}) *{{.Element}} {
y2.Square(x)
y2.Mul(y2, x)
threeX := new({{.Element}}).Add(x, x)
threeX.Add(threeX, x)
y2.Sub(y2, threeX)
return y2.Add(y2, {{.p}}B())
}
func {{.p}}CheckOnCurve(x, y *{{.Element}}) error {
// y² = x³ - 3x + b
rhs := {{.p}}Polynomial(new({{.Element}}), x)
lhs := new({{.Element}}).Square(y)
if rhs.Equal(lhs) != 1 {
return errors.New("{{.P}} point not on curve")
}
return nil
}
// Bytes returns the uncompressed or infinity encoding of p, as specified in
// SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at
// infinity is shorter than all other encodings.
func (p *{{.P}}Point) Bytes() []byte {
// This function is outlined to make the allocations inline in the caller
// rather than happen on the heap.
var out [1+2*{{.p}}ElementLength]byte
return p.bytes(&out)
}
func (p *{{.P}}Point) bytes(out *[1+2*{{.p}}ElementLength]byte) []byte {
if p.z.IsZero() == 1 {
return append(out[:0], 0)
}View on GitHub (pinned to b6b368adc5)
Solutions
- Confirm the (x,y) coordinates came from the same curve as the check function.
- Re-obtain the point from a trusted serialized form via SetBytes which validates internally.
- For externally supplied public keys, run CheckOnCurve and reject on error; do not attempt repair.
- Verify intermediate results of custom scalar multiplication against the curve's own Add/ScalarMult, not hand-rolled field ops.
Example fix
// before
if err := nistec.NewP256Point()./*manual*/; ... // coords hand-assembled
// after (parse through the validated path)
p, err := nistec.NewP256Point().SetBytes(sec1)
if err != nil { return fmt.Errorf("invalid point: %w", err) }
// SetBytes already enforces on-curve; no separate CheckOnCurve needed Defensive patterns
Strategy: try-catch
Validate before calling
// Prefer the validated point parser; explicit CheckOnCurve is rarely needed.
p, err := curve.NewPoint().SetBytes(sec1)
if err != nil { return err } Type guard
func pointOnCurve(p *nistec.P256Point) bool {
// SetBytes already enforces on-curve; this is a defensive secondary check.
return p.Bytes()[0] != 0 || /* infinity allowed */ true
} Try / catch
if err := nistecCheckOnCurve(x, y); err != nil {
return fmt.Errorf("point not on curve: %w", err)
} Prevention
- Route externally supplied points through SetBytes which enforces on-curve.
- Confirm the (x,y) pair originates from the same curve as the check.
- Avoid hand-rolled field arithmetic for point math.
When it happens
Trigger: Passing an (x,y) pair where one coordinate was corrupted, an (x,y) from a different curve, or an uncompressed point whose y was reconstructed incorrectly. Triggered during explicit on-curve verification (not during SetBytes, which already validates).
Common situations: Cross-curve confusion (P-384 point checked against P-256 equation), tampered public key, manual point arithmetic that bypassed the curve's invariants, or test data with a transposed coordinate.
Related errors
- invalid {{ .Element }} encoding
- invalid {{.P}} compressed point encoding
- invalid {{.P}} point encoding
- {{.P}} point is the point at infinity
- invalid scalar length
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/0486f691bf4355de.
Report an issue: GitHub.