diff --git a/src/cashaddrenc.cpp b/src/cashaddrenc.cpp --- a/src/cashaddrenc.cpp +++ b/src/cashaddrenc.cpp @@ -17,26 +17,35 @@ // Size of data-part in a pubkey/script cash address. // Consists of: 8 bits version + 160 bits hash. -const size_t CASHADDR_GROUPED_SIZE = 34; /* 5 bit representation */ -const size_t CASHADDR_BYTES = 21; /* 8 bit representation */ +const size_t CASHADDR_BYTES = 21; /* 8 bit representation */ namespace { // Convert the data part to a 5 bit representation. template -std::vector PackAddrData(const T &id, uint8_t type, - size_t expectedSize) { - std::vector data = {uint8_t(type << 3)}; +std::vector PackAddrData(const T &id, uint8_t type) { + uint8_t version_byte = uint8_t(type << 3); + auto size = id.size(); + auto offset = size > 40 ? 2 : 1; + uint8_t encoded_size = (size - 20 * offset) / (4 * offset); + if (offset == 2) { + encoded_size |= 0x04; + } + if ((size - 20 * offset) % (4 * offset) != 0) { + throw std::runtime_error("Error packing cashaddr: invalid hash length"); + } + if (encoded_size < 0 && encoded_size > 7) { + throw std::runtime_error("Error packing cashaddr: invalid hash length"); + } + + version_byte |= encoded_size; + std::vector data = {version_byte}; data.insert(data.end(), id.begin(), id.end()); std::vector converted; - converted.reserve(expectedSize); + converted.reserve((size + 1) * 8 / 5); ConvertBits<8, 5, true>(converted, begin(data), end(data)); - if (converted.size() != expectedSize) { - throw std::runtime_error("Error packing cashaddr"); - } - return converted; } @@ -46,14 +55,12 @@ CashAddrEncoder(const CChainParams &p) : params(p) {} std::string operator()(const CKeyID &id) const { - std::vector data = - PackAddrData(id, PUBKEY_TYPE, CASHADDR_GROUPED_SIZE); + std::vector data = PackAddrData(id, PUBKEY_TYPE); return cashaddr::Encode(params.CashAddrPrefix(), data); } std::string operator()(const CScriptID &id) const { - std::vector data = - PackAddrData(id, SCRIPT_TYPE, CASHADDR_GROUPED_SIZE); + std::vector data = PackAddrData(id, SCRIPT_TYPE); return cashaddr::Encode(params.CashAddrPrefix(), data); }