The current documentation in docs/source/transactions_and_batches.rst states:
The resulting serialized document is signed with the transactor's private
ECDSA key using the secp256k1 curve.
The validator expects a 64 byte "compact" signature. This is a concatenation
of the R and S fields of the signature. Some libraries will include an
additional header byte, recovery ID field, or provide DER encoded signatures.
Sawtooth will reject the signature if it is anything other than 64 bytes.
The following text must be added:
The ECDSA signature must be normalized (also called low-S signature; see for example: https://eklitzke.org/bitcoin-transaction-malleability for the rationale for this normalization). This implies that the ECDSA must compute (R,S) and (R, N-S) where N is the order of the secp256k1 curve and the effective signature is the one with the smallest of S and N-S (i.e. min(S, N-S)). Failing that the transaction signature will get rejected by the validator.If you are using libraries for ECDSA on secp256k1 that derive from the bitcoin secp256k1 library (e.g. Python3 Sawtooh SDK), you don't have to worry about this normalization. However, mbed TLS and openSSL for example are not normalizing the signature this way.
The change must be applied at two places: one for the transaction header signature and one for the batch header signature in the same file.
This fix applies to any version of Sawtooth.