Bitcoin Forum

Bitcoin => Development & Technical Discussion => Topic started by: amaclin on March 16, 2015, 11:03:27 AM



Title: Strict DER signatures
Post by: amaclin on March 16, 2015, 11:03:27 AM
Why IsValidSignatureEncoding (const std::vector<unsigned char> &sig) does not check R & S sizes?
My suggestion below in blue color

bool static IsValidSignatureEncoding(const std::vector<unsigned char> &sig) {
    // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [ S] [sighash]
    // * total-length: 1-byte length descriptor of everything that follows,
    //   excluding the sighash byte.
    // * R-length: 1-byte length descriptor of the R value that follows.
    // * R: arbitrary-length big-endian encoded R value. It must use the shortest
    //   possible encoding for a positive integers (which means no null bytes at
    //   the start, except a single one when the next byte has its highest bit set).
    // * S-length: 1-byte length descriptor of the S value that follows.
    // * S: arbitrary-length big-endian encoded S value. The same rules apply.
    // * sighash: 1-byte value indicating what data is hashed (not part of the DER
    //   signature)

    // Minimum and maximum size constraints.
    if (sig.size() < 9) return false;
    if (sig.size() > 73) return false;

    // A signature is of type 0x30 (compound).
    if (sig[0] != 0x30) return false;

    // Make sure the length covers the entire signature.
    if (sig[1] != sig.size() - 3) return false;

    // Extract the length of the R element.
    unsigned int lenR = sig[3];

    // Make sure the length of the S element is still inside the signature.
    if (5 + lenR >= sig.size()) return false;

    // Extract the length of the S element.
    unsigned int lenS = sig[5 + lenR];

    // Verify that the length of the signature matches the sum of the length
    // of the elements.
    if ((size_t)(lenR + lenS + 7) != sig.size()) return false;
 
    // Check whether the R element is an integer.
    if (sig[2] != 0x02) return false;

    // Zero-length integers are not allowed for R.
    if (lenR == 0) return false;

    // R can not be wider than 32 bytes
    if (lenR > 33 || (lenR==33 && sig[4] != 0x00)) return false;

    // Negative numbers are not allowed for R.
    if (sig[4] & 0x80) return false;

    // Null bytes at the start of R are not allowed, unless R would
    // otherwise be interpreted as a negative number.
    if ((sig[4] == 0x00) && lenR > 1 && !(sig[5] & 0x80)) return false;

    // Check whether the S element is an integer.
    if (sig[lenR + 4] != 0x02) return false;

    // Zero-length integers are not allowed for S.
    if (lenS == 0) return false;

    // S can not be wider than 32 bytes
    if (lenS > 33 || (lenS==33 && sig[lenR + 6] != 0x00)) return false;

    // Negative numbers are not allowed for S.
    if (sig[lenR + 6] & 0x80) return false;

    // Null bytes at the start of S are not allowed, unless S would otherwise be
    // interpreted as a negative number.
    if (lenS > 1 && (sig[lenR + 6] == 0x00) && !(sig[lenR + 7] & 0x80)) return false;

    return true;
}


Title: Re: Strict DER signatures
Post by: ca333 on March 16, 2015, 11:22:42 AM


    // R can not be wider than 32 bytes
    if (lenR > 33 || (lenR==33 && sig[4] != 0x00)) return false;

    // S can not be wider than 32 bytes
    if (lenS > 33 || (lenS==33 && sig[lenR + 6] != 0x00)) return false;



Signature values can be bigger than 32 bytes. For example also 33 bytes is possible when you see header length descriptor in many tx-scripts.

see the inputscripts in this tx: (r sig has 33 bytes - you can also see this from header 0x21)
https://blockchain.info/tx/f5d289e3b96248208ee21208cb9bba75114ebe0d3082e2afc692086d05a5a95f  (https://blockchain.info/tx/f5d289e3b96248208ee21208cb9bba75114ebe0d3082e2afc692086d05a5a95f)




Title: Re: Strict DER signatures
Post by: amaclin on March 16, 2015, 02:47:27 PM
Signature values can be bigger than 32 bytes. For example also 33 bytes is possible when you see header length descriptor in many tx-scripts.
No. Value is always 256 bit (32 bytes).
The encoding can be 33 bytes (with leading zero byte which is useless, because indicates unsigned integer, not a negative)


Title: Re: Strict DER signatures
Post by: gmaxwell on March 16, 2015, 04:31:53 PM
This specific question was previously discussed on bitcoin-development in the thread there.


Title: Re: Strict DER signatures
Post by: doug_armory on March 16, 2015, 04:49:23 PM
This specific question was previously discussed on bitcoin-development in the thread there.

In particular, this message (http://sourceforge.net/p/bitcoin/mailman/message/33266572/) from sipa explains everything.


Title: Re: Strict DER signatures
Post by: ca333 on March 16, 2015, 05:11:28 PM
Signature values can be bigger than 32 bytes. For example also 33 bytes is possible when you see header length descriptor in many tx-scripts.
No. Value is always 256 bit (32 bytes).
The encoding can be 33 bytes (with leading zero byte which is useless, because indicates unsigned integer, not a negative)

thanks for clarification.
will mark this: 33 bytes with leading zero byte. i always thought the 0-prepad is also part of the sig, because the header lenght descriptor tells me how many bytes are used for the sig-value. and in the above example i see 0x21 (33 byte) for lenght descriptor which i have thought means the lenght of the r-sig is 33 bytes.

This specific question was previously discussed on bitcoin-development in the thread there.

In particular, this message (http://sourceforge.net/p/bitcoin/mailman/message/33266572/) from sipa explains everything.

thank you for posting this. makes it all clear.