isTxDER static method

bool isTxDER(
  1. String buffer
)

ported from moneybutton/bsv This function is translated from bitcoind's IsDERSignature and is used in the script interpreter. This 'DER' format actually includes an extra byte, the nhashtype, at the end. It is really the tx format, not DER format.

A canonical signature exists of: [30] [total len] [02] [len R] [R] [02] [len S] [S] [hashtype]
Where R and S are not negative (their first byte has its highest bit not set), and not
excessively padded (do not start with a 0 byte, unless an otherwise negative number follows,
in which case a single 0 byte is necessary and even required).

See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623

Implementation

static bool isTxDER(String buffer) {
    List<int> buf;
    try {
        buf = HEX.decode(buffer);
    } catch (ex) {
        return false;
    }

    if (buf.length < 9) {
        //  Non-canonical signature: too short
        return false;
    }
    if (buf.length > 73) {
        // Non-canonical signature: too long
        return false;
    }
    if (buf[0] != 0x30) {
        //  Non-canonical signature: wrong type
        return false;
    }
    if (buf[1] != buf.length - 3) {
        //  Non-canonical signature: wrong length marker
        return false;
    }
    var nLenR = buf[3];
    if (5 + nLenR >= buf.length) {
        //  Non-canonical signature: S length misplaced
        return false;
    }
    var nLenS = buf[5 + nLenR];
    if ((nLenR + nLenS + 7) != buf.length) {
        //  Non-canonical signature: R+S length mismatch
        return false;
    }

    var R = buf.sublist(4, buf.length);
    if (buf[4 - 2] != 0x02) {
        //  Non-canonical signature: R value type mismatch
        return false;
    }
    if (nLenR == 0) {
        //  Non-canonical signature: R length is zero
        return false;
    }
    if (R[0] & 0x80 != 0) {
        //  Non-canonical signature: R value negative
        return false;
    }
    if (nLenR > 1 && (R[0] == 0x00) && !(R[1] & 0x80 != 0)) {
        //  Non-canonical signature: R value excessively padded
        return false;
    }

    var S = buf.sublist(6 + nLenR, buf.length);
    if (buf[6 + nLenR - 2] != 0x02) {
        //  Non-canonical signature: S value type mismatch
        return false;
    }
    if (nLenS == 0) {
        //  Non-canonical signature: S length is zero
        return false;
    }
    if (S[0] & 0x80 != 0) {
        //  Non-canonical signature: S value negative
        return false;
    }
    if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80 != 0)) {
        //  Non-canonical signature: S value excessively padded
        return false;
    }
    return true;
}