golang/go · error

negative coordinate

Error message

negative coordinate

What it means

Thrown by nistCurve.pointFromAffine (nistec.go:143) when either X or Y of a point passed to the nistec backend is negative. This is the elliptic-layer sibling of ecdsa error 241: it guards the same fixed-width encoding, but at the elliptic.Curve abstraction level used by crypto/ecdsa, crypto/tls, and crypto/x509.

Source

Thrown at src/crypto/elliptic/nistec.go:143

func (curve *nistCurve[Point]) IsOnCurve(x, y *big.Int) bool {
	// IsOnCurve is documented to reject (0, 0), the conventional point at
	// infinity, which however is accepted by pointFromAffine.
	if x.Sign() == 0 && y.Sign() == 0 {
		return false
	}
	_, err := curve.pointFromAffine(x, y)
	return err == nil
}

func (curve *nistCurve[Point]) pointFromAffine(x, y *big.Int) (p Point, err error) {
	// (0, 0) is by convention the point at infinity, which can't be represented
	// in affine coordinates. See Issue 37294.
	if x.Sign() == 0 && y.Sign() == 0 {
		return curve.newPoint(), nil
	}
	// Reject values that would not get correctly encoded.
	if x.Sign() < 0 || y.Sign() < 0 {
		return p, errors.New("negative coordinate")
	}
	if x.BitLen() > curve.params.BitSize || y.BitLen() > curve.params.BitSize {
		return p, errors.New("overflowing coordinate")
	}
	// Encode the coordinates and let SetBytes reject invalid points.
	byteLen := (curve.params.BitSize + 7) / 8
	buf := make([]byte, 1+2*byteLen)
	buf[0] = 4 // uncompressed point
	x.FillBytes(buf[1 : 1+byteLen])
	y.FillBytes(buf[1+byteLen : 1+2*byteLen])
	return curve.newPoint().SetBytes(buf)
}

func (curve *nistCurve[Point]) pointToAffine(p Point) (x, y *big.Int) {
	out := p.Bytes()
	if len(out) == 1 && out[0] == 0 {
		// This is the encoding of the point at infinity, which the affine
		// coordinates API represents as (0, 0) by convention.

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Reduce coordinates modulo the field prime (x.Mod(x, P)) before any elliptic curve call.
  2. Parse points with elliptic.Unmarshal / standard ASN.1 rather than constructing them from raw big.Int.
  3. Validate x.Sign() >= 0 && y.Sign() >= 0 at the trust boundary.

Example fix

// before
x := new(big.Int).Sub(a, b) // may be negative
px, py := curve.ScalarMult(x, y, k) // -> error 253

// after
P := curve.Params().P
x.Mod(x, P)
px, py := curve.ScalarMult(x, y, k)
Defensive patterns

Strategy: validation

Validate before calling

if x.Sign() < 0 || y.Sign() < 0 {
    return errors.New("elliptic coordinates must be non-negative")
}

Type guard

func nonNegativeEC(x, y *big.Int) bool {
    return x != nil && y != nil && x.Sign() >= 0 && y.Sign() >= 0
}

Prevention

When it happens

Trigger: Reached via elliptic curve operations (Unmarshal, Add, ScalarMult on a nistCurve) and indirectly through ecdsa. Triggered when x.Sign() < 0 || y.Sign() < 0 after excluding the (0,0) infinity convention. Happens with hand-built points or arithmetic that left a coordinate negative.

Common situations: Custom elliptic-curve code using big.Int subtraction without a final Mod into the field; importing points from formats that permit a sign; interop with a library producing signed field elements.

Related errors


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