]> Git Repo - VerusCoin.git/blame - src/key_io.cpp
Use boost::variant to represent shielded addresses and keys
[VerusCoin.git] / src / key_io.cpp
CommitLineData
3d31e09c
PW
1// Copyright (c) 2014-2016 The Bitcoin Core developers
2// Copyright (c) 2016-2018 The Zcash developers
3// Distributed under the MIT software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6#include <key_io.h>
7
8#include <base58.h>
9#include <bech32.h>
10#include <script/script.h>
11#include <utilstrencodings.h>
12
13#include <boost/variant/apply_visitor.hpp>
14#include <boost/variant/static_visitor.hpp>
15
16#include <assert.h>
17#include <string.h>
18#include <algorithm>
19
20namespace
21{
22class DestinationEncoder : public boost::static_visitor<std::string>
23{
24private:
25 const CChainParams& m_params;
26
27public:
28 DestinationEncoder(const CChainParams& params) : m_params(params) {}
29
30 std::string operator()(const CKeyID& id) const
31 {
32 std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
33 data.insert(data.end(), id.begin(), id.end());
34 return EncodeBase58Check(data);
35 }
36
37 std::string operator()(const CScriptID& id) const
38 {
39 std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
40 data.insert(data.end(), id.begin(), id.end());
41 return EncodeBase58Check(data);
42 }
43
44 std::string operator()(const CNoDestination& no) const { return {}; }
45};
46
47CTxDestination DecodeDestination(const std::string& str, const CChainParams& params)
48{
49 std::vector<unsigned char> data;
50 uint160 hash;
51 if (DecodeBase58Check(str, data)) {
52 // base58-encoded Bitcoin addresses.
53 // Public-key-hash-addresses have version 0 (or 111 testnet).
54 // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
55 const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
56 if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
57 std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
58 return CKeyID(hash);
59 }
60 // Script-hash-addresses have version 5 (or 196 testnet).
61 // The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
62 const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
63 if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
64 std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
65 return CScriptID(hash);
66 }
67 }
68 return CNoDestination();
69}
e5eab182
JG
70
71class PaymentAddressEncoder : public boost::static_visitor<std::string>
72{
73private:
74 const CChainParams& m_params;
75
76public:
77 PaymentAddressEncoder(const CChainParams& params) : m_params(params) {}
78
79 std::string operator()(const libzcash::SproutPaymentAddress& zaddr) const
80 {
81 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
82 ss << zaddr;
83 std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS);
84 data.insert(data.end(), ss.begin(), ss.end());
85 return EncodeBase58Check(data);
86 }
87
88 std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
89};
90
91class ViewingKeyEncoder : public boost::static_visitor<std::string>
92{
93private:
94 const CChainParams& m_params;
95
96public:
97 ViewingKeyEncoder(const CChainParams& params) : m_params(params) {}
98
99 std::string operator()(const libzcash::SproutViewingKey& vk) const
100 {
101 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
102 ss << vk;
103 std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::ZCVIEWING_KEY);
104 data.insert(data.end(), ss.begin(), ss.end());
105 std::string ret = EncodeBase58Check(data);
106 memory_cleanse(data.data(), data.size());
107 return ret;
108 }
109
110 std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
111};
112
113class SpendingKeyEncoder : public boost::static_visitor<std::string>
114{
115private:
116 const CChainParams& m_params;
117
118public:
119 SpendingKeyEncoder(const CChainParams& params) : m_params(params) {}
120
121 std::string operator()(const libzcash::SproutSpendingKey& zkey) const
122 {
123 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
124 ss << zkey;
125 std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::ZCSPENDING_KEY);
126 data.insert(data.end(), ss.begin(), ss.end());
127 std::string ret = EncodeBase58Check(data);
128 memory_cleanse(data.data(), data.size());
129 return ret;
130 }
131
132 std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
133};
3d31e09c
PW
134} // namespace
135
136CKey DecodeSecret(const std::string& str)
137{
138 CKey key;
139 std::vector<unsigned char> data;
140 if (DecodeBase58Check(str, data)) {
141 const std::vector<unsigned char>& privkey_prefix = Params().Base58Prefix(CChainParams::SECRET_KEY);
142 if ((data.size() == 32 + privkey_prefix.size() || (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) &&
143 std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) {
144 bool compressed = data.size() == 33 + privkey_prefix.size();
145 key.Set(data.begin() + privkey_prefix.size(), data.begin() + privkey_prefix.size() + 32, compressed);
146 }
147 }
148 memory_cleanse(data.data(), data.size());
149 return key;
150}
151
152std::string EncodeSecret(const CKey& key)
153{
154 assert(key.IsValid());
155 std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::SECRET_KEY);
156 data.insert(data.end(), key.begin(), key.end());
157 if (key.IsCompressed()) {
158 data.push_back(1);
159 }
160 std::string ret = EncodeBase58Check(data);
161 memory_cleanse(data.data(), data.size());
162 return ret;
163}
164
165CExtPubKey DecodeExtPubKey(const std::string& str)
166{
167 CExtPubKey key;
168 std::vector<unsigned char> data;
169 if (DecodeBase58Check(str, data)) {
170 const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
171 if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
172 key.Decode(data.data() + prefix.size());
173 }
174 }
175 return key;
176}
177
178std::string EncodeExtPubKey(const CExtPubKey& key)
179{
180 std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
181 size_t size = data.size();
182 data.resize(size + BIP32_EXTKEY_SIZE);
183 key.Encode(data.data() + size);
184 std::string ret = EncodeBase58Check(data);
185 return ret;
186}
187
188CExtKey DecodeExtKey(const std::string& str)
189{
190 CExtKey key;
191 std::vector<unsigned char> data;
192 if (DecodeBase58Check(str, data)) {
193 const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
194 if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
195 key.Decode(data.data() + prefix.size());
196 }
197 }
198 return key;
199}
200
201std::string EncodeExtKey(const CExtKey& key)
202{
203 std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
204 size_t size = data.size();
205 data.resize(size + BIP32_EXTKEY_SIZE);
206 key.Encode(data.data() + size);
207 std::string ret = EncodeBase58Check(data);
208 memory_cleanse(data.data(), data.size());
209 return ret;
210}
211
212std::string EncodeDestination(const CTxDestination& dest)
213{
214 return boost::apply_visitor(DestinationEncoder(Params()), dest);
215}
216
217CTxDestination DecodeDestination(const std::string& str)
218{
219 return DecodeDestination(str, Params());
220}
221
222bool IsValidDestinationString(const std::string& str, const CChainParams& params)
223{
224 return IsValidDestination(DecodeDestination(str, params));
225}
226
227bool IsValidDestinationString(const std::string& str)
228{
229 return IsValidDestinationString(str, Params());
230}
231
232std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr)
233{
e5eab182 234 return boost::apply_visitor(PaymentAddressEncoder(Params()), zaddr);
3d31e09c
PW
235}
236
e5eab182 237libzcash::PaymentAddress DecodePaymentAddress(const std::string& str)
3d31e09c
PW
238{
239 std::vector<unsigned char> data;
240 if (DecodeBase58Check(str, data)) {
241 const std::vector<unsigned char>& zaddr_prefix = Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS);
242 if ((data.size() == libzcash::SerializedPaymentAddressSize + zaddr_prefix.size()) &&
243 std::equal(zaddr_prefix.begin(), zaddr_prefix.end(), data.begin())) {
244 CSerializeData serialized(data.begin() + zaddr_prefix.size(), data.end());
245 CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
e5eab182 246 libzcash::SproutPaymentAddress ret;
3d31e09c
PW
247 ss >> ret;
248 return ret;
249 }
250 }
e5eab182
JG
251 return libzcash::InvalidEncoding();
252}
253
254bool IsValidPaymentAddressString(const std::string& str) {
255 return IsValidPaymentAddress(DecodePaymentAddress(str));
3d31e09c
PW
256}
257
258std::string EncodeViewingKey(const libzcash::ViewingKey& vk)
259{
e5eab182 260 return boost::apply_visitor(ViewingKeyEncoder(Params()), vk);
3d31e09c
PW
261}
262
e5eab182 263libzcash::ViewingKey DecodeViewingKey(const std::string& str)
3d31e09c
PW
264{
265 std::vector<unsigned char> data;
266 if (DecodeBase58Check(str, data)) {
267 const std::vector<unsigned char>& vk_prefix = Params().Base58Prefix(CChainParams::ZCVIEWING_KEY);
268 if ((data.size() == libzcash::SerializedViewingKeySize + vk_prefix.size()) &&
269 std::equal(vk_prefix.begin(), vk_prefix.end(), data.begin())) {
270 CSerializeData serialized(data.begin() + vk_prefix.size(), data.end());
271 CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
e5eab182 272 libzcash::SproutViewingKey ret;
3d31e09c
PW
273 ss >> ret;
274 memory_cleanse(serialized.data(), serialized.size());
275 memory_cleanse(data.data(), data.size());
276 return ret;
277 }
278 }
279 memory_cleanse(data.data(), data.size());
e5eab182 280 return libzcash::InvalidEncoding();
3d31e09c
PW
281}
282
283std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey)
284{
e5eab182 285 return boost::apply_visitor(SpendingKeyEncoder(Params()), zkey);
3d31e09c
PW
286}
287
e5eab182 288libzcash::SpendingKey DecodeSpendingKey(const std::string& str)
3d31e09c
PW
289{
290 std::vector<unsigned char> data;
291 if (DecodeBase58Check(str, data)) {
292 const std::vector<unsigned char>& zkey_prefix = Params().Base58Prefix(CChainParams::ZCSPENDING_KEY);
293 if ((data.size() == libzcash::SerializedSpendingKeySize + zkey_prefix.size()) &&
294 std::equal(zkey_prefix.begin(), zkey_prefix.end(), data.begin())) {
295 CSerializeData serialized(data.begin() + zkey_prefix.size(), data.end());
296 CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
e5eab182 297 libzcash::SproutSpendingKey ret;
3d31e09c
PW
298 ss >> ret;
299 memory_cleanse(serialized.data(), serialized.size());
300 memory_cleanse(data.data(), data.size());
301 return ret;
302 }
303 }
304 memory_cleanse(data.data(), data.size());
e5eab182 305 return libzcash::InvalidEncoding();
3d31e09c 306}
This page took 0.052979 seconds and 4 git commands to generate.