golang/go · error
invalid signature
Error message
invalid signature
What it means
Returned by the s390x (IBM Z) hardware-accelerated ECDSA verify path when a signature's R or S component byte length exceeds the KDSA instruction's blockSize for the curve (32 for P-256, 48 for P-384, 80 for P-521). Since a canonical scalar mod n always fits in blockSize bytes, an oversized component cannot be a valid signature and is rejected before the KDSA call (which would otherwise panic in appendBlock).
Source
Thrown at src/crypto/internal/fips140/ecdsa/ecdsa_s390x.go:173
}
return &Signature{R: r, S: s}, nil
case 1: // error
return nil, errors.New("zero parameter")
case 2: // retry
continue
}
}
}
func verify[P Point[P]](c *Curve[P], pub *PublicKey, hash []byte, sig *Signature) error {
functionCode, blockSize, ok := canUseKDSA(c.curve)
if !ok {
return verifyGeneric(c, pub, hash, sig)
}
r, s := sig.R, sig.S
if len(r) > blockSize || len(s) > blockSize {
return errors.New("invalid signature")
}
// The parameter block looks like the following for verify:
// +---------------------+
// | Signature(R) |
// +---------------------+
// | Signature(S) |
// +---------------------+
// | Hashed Message |
// +---------------------+
// | Public Key X |
// +---------------------+
// | Public Key Y |
// +---------------------+
// | |
// | ... |
// | |
// +---------------------+View on GitHub (pinned to b6b368adc5)
Solutions
- Ensure R and S are decoded and stored as fixed-width big-endian byte slices whose length matches blockSize (right-aligned, zero-padded on the left).
- If you control encoding, use the curve's signature-marshal helpers (e.g. SignASN1 / VerifyASN1) rather than constructing Signature{R,S} manually.
- On non-s390x targets this path is unreachable; reproduce on real IBM Z hardware or under qemu-s390x to debug.
Example fix
// before: r and s are raw *big.Int byte slices of arbitrary length
sig := &ecdsa.Signature{R: rawR, S: rawS}
return ecdsa.Verify(pub, hash, sig)
// after: normalize to fixed-width big-endian of blockSize
r := fixedWidth(rawR, blockSize)
s := fixedWidth(rawS, blockSize)
// where fixedWidth left-pads with zeros and errors if input exceeds blockSize Defensive patterns
Strategy: validation
Validate before calling
// Before calling ecdsa.Verify with a manually built Signature on s390x:
bs := blockSizeForCurve(curve) // 32 / 48 / 80
if len(sig.R) > bs || len(sig.S) > bs {
return fmt.Errorf("signature R/S exceeds curve block size %d", bs)
}
return ecdsa.Verify(pub, hash, sig) Try / catch
// Go: check err from Verify; treat invalid-signature errors as auth failure.
if err := ecdsa.Verify(pub, hash, sig); err != nil {
// err may be 'invalid signature' from oversized R/S or KDSA rejection
return fmt.Errorf("signature rejected: %w", err)
} Prevention
- Prefer SignASN1/VerifyASN1 to avoid manual R/S byte handling.
- When assembling raw signatures, normalize R and S to fixed-width big-endian of the curve's blockSize.
- On IBM Z, exercise both the KDSA and generic paths in tests to catch encoding bugs.
When it happens
Trigger: Calling ecdsa.Verify (or the internal verify) on s390x hardware where supportsKDSA is true, with a Signature whose R or S fields were assembled from malformed/un-trimmed big-endian byte slices longer than the curve's blockSize.
Common situations: Decoding an ASN.1 DER signature whose integers were not left-trimmed of zero padding into fixed-size buffers; copying a P-521 raw R/S (66 bytes) without zero-padding into an 80-byte block; interoperating with a peer that pads integers to the field size rather than the order size.
Related errors
- invalid ASN.1
- ecdsa: invalid signature: r is zero
- ecdsa: invalid signature: s is zero
- ecdsa: signature did not verify
- ed25519: bad signature length: {l}
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/2ce1b365890049d0.
Report an issue: GitHub.