forked from bitcoin/bitcoin
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
163 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
#include <base58.h> | ||
#include <util/base58_address.h> | ||
#include <boost/test/unit_test.hpp> | ||
|
||
#include <string> | ||
|
||
BOOST_AUTO_TEST_SUITE(base58_prefix_decode_test) | ||
|
||
BOOST_AUTO_TEST_CASE(base58_prefix_decode_testvectors_valid) | ||
{ | ||
const std::string base58_address_std = "12higDjoCCNXSA95xZMWUdPvXNmkAduhWv"; | ||
|
||
static const unsigned char CASES[] = { | ||
0x00, // Mainnet pay to public key hash | ||
0x01, // Largest range of prefixes | ||
0x02, // Second largest range of prefixes | ||
0x03, | ||
0x04, | ||
0x05, // Mainnet script hash | ||
0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, | ||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, | ||
0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, | ||
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, | ||
0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, | ||
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, | ||
0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, | ||
0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, | ||
0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, | ||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, | ||
0x6A, 0x6B, 0x6C, 0x6D, 0x6E, | ||
0x6F, // Testnet pubkey hash | ||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, | ||
0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, | ||
0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, | ||
0x8E, 0x8F, 0x90, | ||
0xC4, // Testnet script hash | ||
0xFF // End of possible range of inputs | ||
}; | ||
|
||
static const std::vector<char> RANGES[] = { | ||
{'1'}, | ||
{'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','m','n','o'}, | ||
{'o','p','q','r','s','t','u','v','w','x','y','z','2'}, | ||
{'2'}, | ||
{'2','3'}, | ||
{'3'}, | ||
{'3'},{'3','4'},{'4'},{'4','5'},{'5'},{'5'},{'5','6'},{'6'},{'6','7'},{'7'}, // Prefix values 6-15 | ||
{'7'},{'7','8'},{'8'},{'8','9'},{'9'},{'9'},{'9','A'},{'A'},{'A','B'},{'B'}, // Prefix values 16-25 | ||
{'B'},{'B','C'},{'C'},{'C','D'},{'D'},{'D'},{'D','E'},{'E'},{'E','F'},{'F'}, // Prefix values 26-35 | ||
{'F'},{'F','G'},{'G'},{'G','H'},{'H'},{'H'},{'H','J'},{'J'},{'J','K'},{'K'}, // Prefix values 36-45 | ||
{'K'},{'K','L'},{'L'},{'L','M'},{'M'},{'M'},{'M','N'},{'N'},{'N','P'},{'P'}, // Prefix values 46-55 | ||
{'P'},{'P','Q'},{'Q'},{'Q','R'},{'R'},{'R'},{'R','S'},{'S'},{'S','T'},{'T'}, // Prefix values 56-65 | ||
{'T'},{'T','U'},{'U'},{'U','V'},{'V'},{'V'},{'V','W'},{'W'},{'W','X'},{'X'}, // Prefix values 66-75 | ||
{'X'},{'X','Y'},{'Y'},{'Y','Z'},{'Z'},{'Z'},{'Z','a'},{'a'},{'a','b'},{'b'}, // Prefix values 76-85 | ||
{'b','c'},{'c'},{'c'},{'c','d'},{'d'},{'d','e'},{'e'},{'e'},{'e','f'},{'f'}, // Prefix values 86-95 | ||
{'f','g'},{'g'},{'g'},{'g','h'},{'h'},{'h','i'},{'i'},{'i'},{'i','j'},{'j'}, // Prefix values 96-105 | ||
{'j','k'},{'k'},{'k'},{'k','m'},{'m'},{'m','n'},{'n'},{'n'},{'n','o'},{'o'}, // Prefix values 106-115 | ||
{'o','p'},{'p'},{'p'},{'p','q'},{'q'},{'q','r'},{'r'},{'r'},{'r','s'},{'s'}, // Prefix values 116-125 | ||
{'s','t'},{'t'},{'t'},{'t','u'},{'u'},{'u','v'},{'v'},{'v'},{'v','w'},{'w'}, // Prefix values 126-135 | ||
{'w','x'},{'x'},{'x'},{'x','y'},{'y'},{'y','z'},{'z'},{'z'},{'z','2'}, // Prefix values 136-144 | ||
{'2'}, | ||
{'2'} | ||
}; | ||
|
||
|
||
static_assert(std::size(CASES) == std::size(RANGES), "Base58 CASES and RANGES should have the same length"); | ||
|
||
std::vector<unsigned char> base58_data; | ||
bool valid_base58 = DecodeBase58(base58_address_std, base58_data, 25); | ||
BOOST_CHECK(valid_base58 == true); | ||
|
||
/* variable output 25 byte decoded base58 cases */ | ||
int i = 0; | ||
for (const unsigned version_byte : CASES) { | ||
std::vector<char> prefixes = Base58PrefixesFromVersionByte(base58_data.size(), version_byte); | ||
std::vector<char> range = RANGES[i]; | ||
BOOST_CHECK_MESSAGE(prefixes == range, "Base58 prefix decoder, version byte " << (uint8_t)version_byte << " prefixes " << std::string(prefixes.begin(),prefixes.end()) << " != " << std::string(range.begin(),range.end()) << " with a total len. of 25"); | ||
++i; | ||
} | ||
|
||
/* static output 25 byte decoded base58 cases */ | ||
for (unsigned short version_byte = 0x91; version_byte <= 0xFF; version_byte++) { | ||
std::vector<char> prefixes = Base58PrefixesFromVersionByte(base58_data.size(), version_byte); | ||
std::vector<char> expected(1,'2'); | ||
BOOST_CHECK_MESSAGE(prefixes == expected, "Base58 prefix decoder, version byte " << (uint8_t)version_byte << " prefixes " << std::string(prefixes.begin(),prefixes.end()) << " != " << std::string(expected.begin(),expected.end()) << " with a total len. of 25"); | ||
} | ||
} | ||
|
||
BOOST_AUTO_TEST_SUITE_END() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// Copyright (c) 2023 The Bitcoin Core developers | ||
// Distributed under the MIT software license, see the accompanying | ||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
|
||
#include <base58.h> | ||
#include <util/base58_address.h> | ||
|
||
#include <algorithm> | ||
|
||
std::vector<char> Base58PrefixesFromVersionByte(size_t length, unsigned char version_byte) | ||
{ | ||
std::vector<char> base58_prefix_char_range; | ||
|
||
if (length) { | ||
static const unsigned char MIN_PAYLOAD_FILL = 0x00; | ||
static const unsigned char MAX_PAYLOAD_FILL = 0xFF; | ||
static const char ENCODED_LEADING_ZEROES = '1'; | ||
|
||
const std::vector<unsigned char> payload_range = { MIN_PAYLOAD_FILL, MAX_PAYLOAD_FILL }; | ||
std::vector<unsigned char> base58_prefix_min_max; | ||
|
||
for (const auto& payload : payload_range) { | ||
std::vector<unsigned char> range_test_bound(std::max(1, (int)length), payload); | ||
range_test_bound.at(0) = version_byte; | ||
base58_prefix_min_max.emplace_back(EncodeBase58(range_test_bound).at(0)); | ||
} | ||
|
||
auto IsBase58Char = [&](char c) { return std::string_view(pszBase58).find_first_of(c) != std::string::npos; }; | ||
|
||
if (base58_prefix_min_max.front() == ENCODED_LEADING_ZEROES) { | ||
base58_prefix_char_range.emplace_back(base58_prefix_min_max.front()); | ||
} else if(IsBase58Char(base58_prefix_min_max.front()) && IsBase58Char(base58_prefix_min_max.back())) { | ||
for (int i = 1; pszBase58[i] != '\0'; i++) { | ||
base58_prefix_char_range.emplace_back(pszBase58[i]); | ||
} | ||
auto start_position = std::find(base58_prefix_char_range.begin(), base58_prefix_char_range.end(), base58_prefix_min_max.front()); | ||
std::rotate(base58_prefix_char_range.begin(), start_position, base58_prefix_char_range.end()); | ||
base58_prefix_char_range.erase(++std::find(base58_prefix_char_range.begin(), base58_prefix_char_range.end(), base58_prefix_min_max.back()), base58_prefix_char_range.end()); | ||
} | ||
} | ||
|
||
return base58_prefix_char_range; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// Copyright (c) 2023 The Bitcoin Core developers | ||
// Distributed under the MIT software license, see the accompanying | ||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
|
||
#ifndef BITCOIN_UTIL_BASE58_ADDRESS_H | ||
#define BITCOIN_UTIL_BASE58_ADDRESS_H | ||
|
||
#include <cstddef> | ||
#include <vector> | ||
|
||
/** Derives the first Base58 character prefixes for a given version byte and a length | ||
* | ||
* @param[in] length length of pre-encoded base58 data | ||
* @param[in] version_byte The address version byte | ||
* @param[out] The possible range of base58 prefixes (eg. ['m','n']) | ||
* @code | ||
* std::vector result = Base58PrefixesFromVersionByte(31,0x05); | ||
* // result will be ['3'] | ||
* @endcode | ||
*/ | ||
std::vector<char> Base58PrefixesFromVersionByte(size_t length, unsigned char version_byte); | ||
|
||
#endif // BITCOIN_UTIL_BASE58_ADDRESS_H |