golang/go · error

invalid P256 element encoding

Error message

invalid P256 element encoding

What it means

During uncompressed P-256 point decoding (65-byte input with 0x04 prefix), each coordinate is range-checked against the field prime p via p256LessThanP. If either x or y is >= p, the encoding is rejected as invalid because field elements must be strictly less than the modulus. This prevents a class of invalid-curve and small-subgroup attacks.

Source

Thrown at src/crypto/internal/fips140/nistec/p256_asm.go:97

	// This implementation operates in the Montgomery domain with R = 2²⁵⁶ mod
	// p. Elements in the Montgomery domain take the form a×R and p256Mul
	// calculates (a × b × R⁻¹) mod p. rr is R in the domain, or R×R mod p, thus
	// p256Mul(e, RR) gives e×R, i.e. converts e into the Montgomery domain.
	rr := p256Element{0x0000000000000003, 0xfffffffbffffffff,
		0xfffffffffffffffe, 0x00000004fffffffd}

	switch {
	// Point at infinity.
	case len(b) == 1 && b[0] == 0:
		return p.Set(NewP256Point()), nil

	// Uncompressed form.
	case len(b) == p256UncompressedLength && b[0] == 4:
		var r P256Point
		p256BigToLittle(&r.x, (*[32]byte)(b[1:33]))
		p256BigToLittle(&r.y, (*[32]byte)(b[33:65]))
		if p256LessThanP(&r.x) == 0 || p256LessThanP(&r.y) == 0 {
			return nil, errors.New("invalid P256 element encoding")
		}
		p256Mul(&r.x, &r.x, &rr)
		p256Mul(&r.y, &r.y, &rr)
		if err := p256CheckOnCurve(&r.x, &r.y); err != nil {
			return nil, err
		}
		r.z = p256One
		return p.Set(&r), nil

	// Compressed form.
	case len(b) == p256CompressedLength && (b[0] == 2 || b[0] == 3):
		var r P256Point
		p256BigToLittle(&r.x, (*[32]byte)(b[1:33]))
		if p256LessThanP(&r.x) == 0 {
			return nil, errors.New("invalid P256 element encoding")
		}
		p256Mul(&r.x, &r.x, &rr)

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Validate or re-fetch the public key from a trusted source
  2. Ensure coordinates are big-endian and within [0, p-1] before encoding
  3. Use higher-level crypto/ecdsa or crypto/ecdh APIs which handle validation internally
  4. Check for transmission corruption by verifying a checksum or signature over the key
Defensive patterns

Strategy: validation

Validate before calling

// Validate an uncompressed P-256 point encoding before SetBytes.
// Note: full on-curve validation is done by the library itself.
func isValidP256Encoding(b []byte) bool {
    if len(b) == 1 && b[0] == 0 { return true } // infinity
    if len(b) == 65 && b[0] == 0x04 { return true }
    if len(b) == 33 && (b[0] == 0x02 || b[0] == 0x03) { return true }
    return false
}

if !isValidP256Encoding(keyBytes) { return errors.New("bad encoding") }
_, err := point.SetBytes(keyBytes) // library does the full field/curve checks

Try / catch

_, err := point.SetBytes(b)
if err != nil {
    // Could be range check, on-curve, or encoding error — all mean reject the key.
    return fmt.Errorf("invalid P-256 point: %w", err)
}

Prevention

When it happens

Trigger: Calling P256Point.SetBytes with a 65-byte uncompressed point where at least one of the 32-byte coordinate fields encodes a value >= the P-256 prime p (0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF).

Common situations: Corrupted or tampered public key bytes; incorrect endianness (little-endian coordinates fed where big-endian is expected); manually constructing point encodings without respecting the field modulus; transmission errors over a network channel.

Related errors


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