Bitcoin ABC 0.34.2
P2P Digital Currency
cashaddrenc.cpp
Go to the documentation of this file.
1// Copyright (c) 2017-2019 The Bitcoin developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4#include <cashaddrenc.h>
5
6#include <addresstype.h>
7#include <cashaddr.h>
8#include <chainparams.h>
9#include <pubkey.h>
10#include <script/script.h>
11#include <util/strencodings.h>
12
13#include <algorithm>
14#include <variant>
15
16namespace {
17
18// Convert the data part to a 5 bit representation.
19template <class T>
20std::vector<uint8_t> PackAddrData(const T &id, uint8_t type) {
21 uint8_t version_byte(type << 3);
22 size_t size = id.size();
23 uint8_t encoded_size = 0;
24 switch (size * 8) {
25 case 160:
26 encoded_size = 0;
27 break;
28 case 192:
29 encoded_size = 1;
30 break;
31 case 224:
32 encoded_size = 2;
33 break;
34 case 256:
35 encoded_size = 3;
36 break;
37 case 320:
38 encoded_size = 4;
39 break;
40 case 384:
41 encoded_size = 5;
42 break;
43 case 448:
44 encoded_size = 6;
45 break;
46 case 512:
47 encoded_size = 7;
48 break;
49 default:
50 throw std::runtime_error(
51 "Error packing cashaddr: invalid address length");
52 }
53 version_byte |= encoded_size;
54 std::vector<uint8_t> data = {version_byte};
55 data.insert(data.end(), std::begin(id), std::end(id));
56
57 std::vector<uint8_t> converted;
58 // Reserve the number of bytes required for a 5-bit packed version of a
59 // hash, with version byte. Add half a byte(4) so integer math provides
60 // the next multiple-of-5 that would fit all the data.
61 converted.reserve(((size + 1) * 8 + 4) / 5);
62 ConvertBits<8, 5, true>([&](uint8_t c) { converted.push_back(c); },
63 std::begin(data), std::end(data));
64
65 return converted;
66}
67
68// Implements encoding of CTxDestination using cashaddr.
69class CashAddrEncoder {
70public:
71 explicit CashAddrEncoder(const CChainParams &p) : params(p) {}
72
73 std::string operator()(const PKHash &id) const {
74 std::vector<uint8_t> data = PackAddrData(id, PUBKEY_TYPE);
75 return cashaddr::Encode(params.CashAddrPrefix(), data);
76 }
77
78 std::string operator()(const ScriptHash &id) const {
79 std::vector<uint8_t> data = PackAddrData(id, SCRIPT_TYPE);
80 return cashaddr::Encode(params.CashAddrPrefix(), data);
81 }
82
83 std::string operator()(const CNoDestination &) const { return ""; }
84
85private:
86 const CChainParams &params;
87};
88
89} // namespace
90
91std::string EncodeCashAddr(const CTxDestination &dst,
92 const CChainParams &params) {
93 return std::visit(CashAddrEncoder(params), dst);
94}
95
96std::string EncodeCashAddr(const std::string &prefix,
97 const CashAddrContent &content) {
98 std::vector<uint8_t> data = PackAddrData(content.hash, content.type);
99 return cashaddr::Encode(prefix, data);
100}
101
102CTxDestination DecodeCashAddr(const std::string &addr,
103 const CChainParams &params) {
104 CashAddrContent content =
106 if (content.hash.size() == 0) {
107 return CNoDestination{};
108 }
109
110 return DecodeCashAddrDestination(content);
111}
112
114 const std::string &expectedPrefix) {
115 auto [prefix, payload] = cashaddr::Decode(addr, expectedPrefix);
116
117 if (prefix != expectedPrefix) {
118 return {};
119 }
120
121 if (payload.empty()) {
122 return {};
123 }
124
125 std::vector<uint8_t> data;
126 data.reserve(payload.size() * 5 / 8);
127 if (!ConvertBits<5, 8, false>([&](uint8_t c) { data.push_back(c); },
128 begin(payload), end(payload))) {
129 return {};
130 }
131
132 // Decode type and size from the version.
133 uint8_t version = data[0];
134 if (version & 0x80) {
135 // First bit is reserved.
136 return {};
137 }
138
139 auto type = CashAddrType((version >> 3) & 0x1f);
140 uint32_t hash_size = 20 + 4 * (version & 0x03);
141 if (version & 0x04) {
142 hash_size *= 2;
143 }
144
145 // Check that we decoded the exact number of bytes we expected.
146 if (data.size() != hash_size + 1) {
147 return {};
148 }
149
150 // Pop the version.
151 data.erase(data.begin());
152 return {type, std::move(data)};
153}
154
156 if (content.hash.size() != 20) {
157 // Only 20 bytes hash are supported now.
158 return CNoDestination{};
159 }
160
161 uint160 hash;
162 std::copy(begin(content.hash), end(content.hash), hash.begin());
163
164 switch (content.type) {
165 case PUBKEY_TYPE:
166 return PKHash(hash);
167 case SCRIPT_TYPE:
168 return ScriptHash(hash);
169 default:
170 return CNoDestination{};
171 }
172}
173
174// PackCashAddrContent allows for testing PackAddrData in unittests due to
175// template definitions.
176std::vector<uint8_t> PackCashAddrContent(const CashAddrContent &content) {
177 return PackAddrData(content.hash, content.type);
178}
std::variant< CNoDestination, PKHash, ScriptHash > CTxDestination
A txout script template with a specific destination.
Definition: addresstype.h:54
std::string EncodeCashAddr(const CTxDestination &dst, const CChainParams &params)
Definition: cashaddrenc.cpp:91
CashAddrContent DecodeCashAddrContent(const std::string &addr, const std::string &expectedPrefix)
CTxDestination DecodeCashAddrDestination(const CashAddrContent &content)
CTxDestination DecodeCashAddr(const std::string &addr, const CChainParams &params)
std::vector< uint8_t > PackCashAddrContent(const CashAddrContent &content)
CashAddrType
Definition: cashaddrenc.h:14
@ PUBKEY_TYPE
Definition: cashaddrenc.h:14
@ SCRIPT_TYPE
Definition: cashaddrenc.h:14
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
Definition: chainparams.h:86
const std::string & CashAddrPrefix() const
Definition: chainparams.h:143
constexpr uint8_t * begin()
Definition: uint256.h:122
160-bit opaque blob.
Definition: uint256.h:184
std::pair< std::string, data > Decode(const std::string &str, const std::string &default_prefix)
Decode a cashaddr string.
Definition: cashaddr.cpp:216
std::string Encode(const std::string &prefix, const data &payload)
Encode a cashaddr string.
Definition: cashaddr.cpp:200
const char * prefix
Definition: rest.cpp:1078
CashAddrType type
Definition: cashaddrenc.h:17
std::vector< uint8_t > hash
Definition: cashaddrenc.h:18