SoftwareVerde / bitcoin-cash-specification

Specification of the Bitcoin Cash protocols and consensus
Other
7 stars 5 forks source link

Compact Variable Length Integer (CompactSize) specification misses canonical encoding rules. #41

Open joshmg opened 1 year ago

joshmg commented 1 year ago

The specification of Compact Variable Length Integer (/protocol/formats/variable-length-integer) (also known as "CompactSize" in Core-clients) does not specify that values should be canonically encoded, however this rule is enforced by all Core-derived clients.

E.g. the value 1 must be encoded as 0x01 rather than 0xFD0100, 0xFE0100000, or 0xFF010000000000000.

joshmg commented 1 year ago

The implementation of this functionality within BCHN is as follows:

template <typename Stream> uint64_t ReadCompactSizeWithLimit(Stream &is, const uint64_t maxSize) {
    uint8_t chSize = ser_readdata8(is);
    uint64_t nSizeRet = 0; 
    if (chSize < 253) {
        nSizeRet = chSize;
    } else if (chSize == 253) {
        nSizeRet = ser_readdata16(is);
        if (nSizeRet < 253) {
            throw std::ios_base::failure("non-canonical ReadCompactSize()");
        }
    } else if (chSize == 254) {
        nSizeRet = ser_readdata32(is);
        if (nSizeRet < 0x10000u) {
            throw std::ios_base::failure("non-canonical ReadCompactSize()");
        }
    } else {
        nSizeRet = ser_readdata64(is);
        if (nSizeRet < 0x100000000ULL) {
            throw std::ios_base::failure("non-canonical ReadCompactSize()");
        }
    }    
    if (nSizeRet > maxSize) {
        throw std::ios_base::failure("ReadCompactSize(): size too large");
    }    
    return nSizeRet;
}