golang/go · error

invalid scalar length

Error message

invalid scalar length

What it means

p256OrdElement.SetBytes requires exactly 32 bytes of big-endian input representing a P-256 scalar. The value is then conditionally reduced into [0, ord(G)-1]. Any length other than 32 is rejected because the P-256 scalar field has a fixed 256-bit width and no variable-length encoding is supported.

Source

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

	return q
}

// Select sets q to p1 if cond == 1, and to p2 if cond == 0.
func (q *P256Point) Select(p1, p2 *P256Point, cond int) *P256Point {
	q.x.Select(&p1.x, &p2.x, cond)
	q.y.Select(&p1.y, &p2.y, cond)
	q.z.Select(&p1.z, &p2.z, cond)
	return q
}

// p256OrdElement is a P-256 scalar field element in [0, ord(G)-1]
// as four uint64 limbs in little-endian order.
type p256OrdElement [4]uint64

// SetBytes sets s to the big-endian value of x, reducing it as necessary.
func (s *p256OrdElement) SetBytes(x []byte) (*p256OrdElement, error) {
	if len(x) != 32 {
		return nil, errors.New("invalid scalar length")
	}

	s[0] = byteorder.BEUint64(x[24:])
	s[1] = byteorder.BEUint64(x[16:])
	s[2] = byteorder.BEUint64(x[8:])
	s[3] = byteorder.BEUint64(x[:])

	// Ensure s is in the range [0, ord(G)-1]. Since 2 * ord(G) > 2²⁵⁶, we can
	// just conditionally subtract ord(G), keeping the result if it doesn't
	// underflow.
	t0, b := bits.Sub64(s[0], 0xf3b9cac2fc632551, 0)
	t1, b := bits.Sub64(s[1], 0xbce6faada7179e84, b)
	t2, b := bits.Sub64(s[2], 0xffffffffffffffff, b)
	t3, b := bits.Sub64(s[3], 0xffffffff00000000, b)
	tMask := b - 1 // zero if subtraction underflowed
	s[0] ^= (t0 ^ s[0]) & tMask
	s[1] ^= (t1 ^ s[1]) & tMask
	s[2] ^= (t2 ^ s[2]) & tMask

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Ensure the scalar byte slice is exactly 32 bytes before calling SetBytes
  2. If the scalar arrives as a big.Int, use bigInt.FillBytes(make([]byte, 32)) to get a fixed-width big-endian encoding
  3. Strip any 0x hex prefix and validate the hex string length is 64 characters before decoding

Example fix

// before
var s p256OrdElement
_, err := s.SetBytes(scalarBytes) // may be wrong length

// after
if len(scalarBytes) != 32 {
    return fmt.Errorf("scalar must be 32 bytes, got %d", len(scalarBytes))
}
fixed := make([]byte, 32)
scalarBigInt.FillBytes(fixed)
_, err := s.SetBytes(fixed)
Defensive patterns

Strategy: validation

Validate before calling

func validateP256Scalar(b []byte) error {
    if len(b) != 32 {
        return fmt.Errorf("scalar must be exactly 32 bytes, got %d", len(b))
    }
    return nil
}

// Usage:
if err := validateP256Scalar(scalarBytes); err != nil { return err }
var s p256OrdElement
_, err := s.SetBytes(scalarBytes)

Try / catch

_, err := s.SetBytes(x)
if err != nil {
    return fmt.Errorf("invalid scalar: %w", err)
}

Prevention

When it happens

Trigger: Calling s.SetBytes(x) where len(x) != 32. This is a low-level scalar-field API used internally; it does not accept padded, truncated, or hex-encoded values.

Common situations: Passing a hex-decoded scalar without stripping the 0x prefix (yields 33 bytes), passing a DER/ASN.1-encoded integer, truncating a key share, or mixing up byte orders between little-endian and big-endian representations.

Related errors


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